This is the mail archive of the cygwin mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: weak symbols on Cygwin

On 07/04/2010 00:41, Bruno Haible wrote:
> Hi Dave,

  Hi Bruno,

> Dave Korn wrote:
>>>> These were all due to the fact that gcc 4.3.x on Cygwin 1.7.2
>>>> accepts "#pragma weak foo", but the symbol foo then evaluates
>>>> to the NULL address, even if foo is defined in libc.
>>> Dave, are weak symbols something that should work on cygwin with new
>>> enough binutils/gcc?  Or is this an indicator of a gcc bug, for silently
>>> accepting #pragma weak foo that it can't support?
>>   Weak symbols work on Cygwin, but the semantics of undefined weak symbols
>> aren't identical to ELF platforms: a weak reference won't pull in an archive
>> member that wouldn't otherwise be linked; the implications in relation to
>> import libraries should be fairly obvious.
> I don't know what semantics is implemented by "#pragma weak" on Cygwin.

  Well, weak symbols on Cygwin are implemented by using the "weak external
symbols" defined in the PE specification.  To save you looking it up: they are
a kind of undefined reference that don't cause a link failure if no definition
is supplied at final link time; instead, they resolve to a default constant
value, generally zero.

> On ELF platforms, I use "#pragma weak" in order to detect whether a symbol
> is defined in the libraries which are linked in with the executable
> (including libc). This does not work on Cygwin: this program
> ======================================================
>    #include <stdio.h>
>    extern void gurky (void);
>    #pragma weak fputs
>    #pragma weak gurky
>    int main ()
>    {
>      printf ("fputs %s, gurky %s\n",
>              fputs != NULL ? "present" : "missing",
>              gurky != NULL ? "present" : "missing");
>      return 0;
>    }
> ======================================================
> compiled and run with
>   $ gcc -o foo foo.c -Wall
>   $ ./foo
> prints on glibc systems:
>   fputs present, gurky missing
> but on Cygwin 1.7.2:
>   fputs missing, gurky missing
> With this inability to distinguish present from missing libc symbols,
> "#pragma weak" is useless to me on Cygwin.

  Ah, but what you're relying on there is not merely the weak symbol aspect of
ELF, but another, far more problematic one to emulate on Windows: the fact
that on ELF platforms, you can leave undefined references in an executable, to
be filled in by at runtime according to what the loader finds present
once it's loaded libc.

  Both fputs and gurky are undefined symbols in the foo executable when you
compile it on Linux.  At runtime, fills in the value for fputs, which it
finds when it loads libc for other reasons, and it doesn't complain that gurky
is undefined because it's a weak symbol.

  On windows, this technique can't work, because every undefined reference in
an executable has to be fully resolved at link-time.  It's the static linker
that has to decide whether there's anything to resolve a weak symbol against,
and if not to resolve the default value.  There's no run-time process of
scanning all available symbols from all loaded libraries against undefined
references in the executable.

  Here's where the subtle semantic difference between weak symbols on ELF and
PE comes in: PE weak symbols don't cause any archive members to be pulled out
of library files into the final link.  And that interacts with another
difference between PE and ELF: on Windows, all the library functions imported
from libc come in the form of import stubs from the (static) import library.
So weak references won't cause any of those symbols to be pulled in, even if
the library does provide them.  But if something else in the program causes
them to be pulled in, the weak references will resolve to the imported
function.  You can see that by adding a second object to your testcase, with a
strong undefined reference:

> $ cat bar.c
> #include <stdio.h>
>   void bar (const char *x)
>   {
>     fputs (x, stdout);
>   }
> $ gcc -o foo  foo.c   -Wall --save-temps
> $ ./foo
> fputs missing, gurky missing
> $ gcc -o foo  foo.c bar.c  -Wall --save-temps
> $ ./foo
> fputs present, gurky missing
> $ 

  (We currently rely on this behaviour to make the libstdc++ malloc wrappers
work: we use weak references to find out what functions a program defines
overrides for, without pulling in unused functions from libstdc++ in their
place.  It's also used in libgcc, which uses a weak reference to tell if the
EH machinery is linked into the application, and call the frame registration
handlers if present, without causing the whole EH machinery to be pulled into
every link.)

  So, it's not really the weakness of the symbols - which really just tells
the linker to shut up and not complain if no definition is provided at link
time - that differs here and causes the problem; it's the whole undefined
references in executables and resolving them by at runtime that your
testcase relies on here to determine the presence or absence of functions in
the library.  Back to your requirements:

> On ELF platforms, I use "#pragma weak" in order to detect whether a symbol
> is defined in the libraries which are linked in with the executable
> (including libc).

  This whole concept isn't going to translate directly to Windows platforms.
There's no interposing or providing missing definitions at runtime; if it's
not already there at final link time, it's not going to be there at runtime.
The only way windows can determine this sort of thing is through dlsym()ing
all the open libraries, I think.

  What's the larger-scale goal you're trying to support by this method?  Are
you after implementing some sort of plug-in architecture or something?


Problem reports:
Unsubscribe info:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]