我的问题可归纳如下:
bar.c :
#include <stdio.h>
void bar() {
printf("bar\n");
}
的main.c :
#include <stdio.h>
void __attribute__((weak)) bar() {
printf("foo\n");
}
int main() {
bar();
return 0;
}
生成文件:
all:
gcc -c bar.c
ar -rc libbar.a bar.o
gcc main.c -L. -lbar
输出:
$ ./a.out
foo
因为bar.c被链接到静态库libbar.a中的main.c,所以main.c中的弱符号栏不会被bar.c中的强符号覆盖。
如何告诉gcc在libbar.a中创建强符号来覆盖main.c中的弱符号?
答案 0 :(得分:27)
我对max.haredoom给出的答案感到困惑(并且它已被接受)。答案涉及共享库和动态链接,而问题显然是关于使用静态库的静态链接的行为。我认为这是误导。
关联静态库时,ld
不关注弱/强符号默认:它只是将未定义的符号解析为第一次遇到的符号(因此命令行中静态库的顺序很重要。)
但是,可以使用--whole-archive
选项更改此默认行为。如果您按如下方式重写Makefile中的最后一步:
gcc main.c -L. -Wl,--whole-archive -lbar -Wl,--no-whole-archive
然后你会看到:
$ ./a.out
bar
简而言之,--whole-archive
强制链接器扫描其所有符号(包括那些已经解析的符号)。如果有一个强符号已经被弱符号解析(如我们的情况),强符号将否定弱符号。
另请参阅有关静态库及其链接过程"Library order in static linking" by Eli Bendersky和this SO question的精彩文章。
答案 1 :(得分:8)
一般来说:如果你没有将弱实现放入main
,链接器最终会在运行时解析它。但是如果你在main.c
中实现它,那么在链接这个静态时,你只能用强绑定(bar.c
)覆盖它。
请阅读http://www.bottomupcs.com/libraries_and_the_linker.html - 它包含很多关于此主题的有趣内容。
我自己做了一个测试:
bar.c
#include <stdio.h>
void bar()
{
puts("bar.c: i'm the strong bar()");
}
baz.c
#include <stdio.h>
void __attribute__((weak)) bar()
{
puts("baz.c: i'm the weak bar()");
}
的main.c
#include <stdio.h>
#ifdef V2
void __attribute__((weak)) bar()
{
puts("main: i'm the build in weak bar()");
}
#else
void __attribute__((weak)) bar();
#endif
int main()
{
bar();
return 0;
}
我的Makefile:
all:
gcc -c -o bar.o bar.c
gcc -shared -fPIC -o libbar.so bar.o
gcc -c -o baz.o baz.c
gcc -shared -fPIC -o libbaz.so baz.o
gcc -o main1 main.c -L. -lbar -lbaz
gcc -o main2 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. ./main1 # => bar.c
LD_LIBRARY_PATH=. ./main2 # => baz.c
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main1 # => baz.c (!!)
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main2 # => baz.c
gcc -o main3 main.c bar.o baz.o
gcc -o main4 main.c baz.o bar.o
./main3 # => bar.c
./main4 # => bar.c
gcc -DV2 -o main5 main.c -L. -lbar -lbaz
gcc -DV2 -o main6 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. ./main5 # => main's implementation
LD_LIBRARY_PATH=. ./main6 # => main's implementation
gcc -DV2 -o main7 main.c -L. -lbar -lbaz
gcc -DV2 -o main8 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main7 # => main's implementation
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main8 # => main's implementation
gcc -DV2 -o main9 main.c -L. -lbar -lbaz
gcc -DV2 -o main10 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main9 # => main's implementation
LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main10 # => main's implementation
gcc -c bar.c
gcc -c baz.c
gcc -o main11 main.c bar.o baz.o
gcc -o main12 main.c baz.o bar.o
./main11 # => bar.c
./main12 # => bar.c
gcc -o main13 -DV2 main.c bar.o baz.o
gcc -o main14 -DV2 main.c baz.o bar.o
./main13 # => bar.c
./main14 # => bar.c
看一下main1&amp;&amp; main2 ...如果你没有将任何弱实现放入main.c
但是将弱者保留在库中而将强者保留在另一个库中,那么如果强大的lib,你将能够覆盖弱者。定义了bar()
的强大实现。