Weak symbol link on Mac OS X
Currently I encountered a weak link issue on Mac OS X 10.6.7 with Xcode 4.0.2.
$ gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
As the developer document said, we can use gcc attribut开发者_开发百科e((weak_import)) for weak link symbol. However, the following sample code always throw compile error.
As the following:weak.c:
#include <stdlib.h>
#include <stdio.h>
extern int SayHello() __attribute__((weak));
int main()
{
int result;
if (SayHello!=NULL)
{
printf("SayHello is present!\n");
result=SayHello();
}
else
printf("SayHello is not present!\n");
}
The error message is the following:
$ gcc weak.c
Undefined symbols for architecture x86_64:
"_f", referenced from:
_main in cceOf2wN.o
(maybe you meant: __dyld_func_lookup)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Even if use option -undefined dynamic_lookup
, it still throws error at runtime:
$ gcc -undefined dynamic_lookup weak.c
$ ./a.out
dyld: Symbol not found: _SayHello
Referenced from: /private/tmp/o/./a.out
Expected in: dynamic lookup
Trace/BPT trap
The nm -m
message of "a.out" is the following:
$ nm -m a.out | grep Hello
(undefined) external _SayHello (dynamically looked up)
Which was expected as the following:
(undefined) weak external _SayHello (dynamically looked up)
However, when I compile on Ubuntu with gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5, it works as expected:
weak.c:
#include <stdlib.h>
#include <stdio.h>
extern int SayHello() __attribute__((weak));
int main()
{
int result;
if (SayHello!=NULL)
{
printf("SayHello is present!\n");
result=SayHello();
}
else
printf("SayHello is not present!\n");
}
$ gcc weak.c
$ ./a.out
SayHello is not present!
The symbol of SayHello in binary is:
$ nm a.out | grep Hello
w SayHello
"w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
And I test the old xcode 3.2, it works as expected.
Could anyone help me on this? Was it a bug of ld?
And I found more interested things. When I create a dummy lib to export the SayHello symbol in dynamic lib, it works as expected.
dummy.c:
int SayHello() {
return;
}
$ gcc -dynamiclib -o libdummy.dylib dummy.c
$ gcc weak.c libdummy.dylib
$ ./a.out
SayHello is present!
If the "libdummy.dylib" does not exist:
$ rm libdummy.dylib
$ ./a.out
SayHello is not present!
Works as expected! Weak symbol now in nm message, as expected:
$ nm -m a.out | grep Hello
(undefined) weak external _SayHello (from libdummy)
This still errors today on GCC 12 and Clang 14 without the -undefined dynamic_lookup
option:
Undefined symbols for architecture arm64:
"_SayHello", referenced from:
_main in weak-518bb6.o
ld: symbol(s) not found for architecture arm64
But it works correctly with the option set:
% gcc-12 -undefined dynamic_lookup -o weak weak.c && ./weak
ld: warning: -undefined dynamic_lookup may not work with chained fixups
SayHello is not present!
% cc -undefined dynamic_lookup -o weak weak.c && ./weak
ld: warning: -undefined dynamic_lookup may not work with chained fixups
SayHello is not present!
gcc-12 (Homebrew GCC 12.2.0) 12.2.0
Apple clang version 14.0.0 (clang-1400.0.29.102)
C0deH4cker called out this link in comments. It walks through the problem in detail including some workarounds.
精彩评论