我对gcc链接顺序有一些疑问。 GCC man表示链接器从左到右搜索符号,默认情况下不重复搜索。这是我的测试:
的main.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("HELLO WROLD\n");
return 0;
}
printf.c
#include <stdio.h>
#include <stdlib.h>
int printf(const char *fmt, ...)
{
write(1, "AAA\n", 4);
}
[root@lenovo testcode]# gcc -c -fno-builtin-printf *.c
[root@lenovo testcode]# gcc -o test main.o printf.o
[root@lenovo testcode]# ./test
AAA
[root@lenovo testcode]# gcc -o test printf.o main.o
[root@lenovo testcode]# ./test
AAA
[root@lenovo testcode]# ar rcs libprintf.a printf.o
[root@lenovo testcode]# gcc -o test libprintf.a main.o
[root@lenovo testcode]# ./test
HELLO WROLD
[root@lenovo testcode]# gcc -o test main.o libprintf.a
[root@lenovo testcode]# ./test
AAA
[root@lenovo testcode]# gcc -shared -o libprintf.so printf.o
[root@lenovo testcode]# gcc -o test libprintf.so main.o
[root@lenovo testcode]# export LD_LIBRARY_PATH=.
[root@lenovo testcode]# ./test
AAA
[root@lenovo testcode]# gcc -o test main.o libprintf.so
[root@lenovo testcode]# ./test
AAA
从结果中,我们可以看到.o和.o,.o和.so的顺序没有区别,只有.o和.a的顺序才有效。但这与gcc手册页不一致。那为什么呢?
答案 0 :(得分:8)
gcc确实从左到右处理目标文件。当你有
gcc -o test libprintf.a main.o
gcc看到的第一个目标文件是libprintf.a
。此时输出对象没有未解析的符号,因此使用/需要libprintf.a
的任何内容。接下来,处理main.o
,链接器记录printf
未解析的事实,然后继续处理隐式库,它可以解析printf
符号未解决的in main.o
。
同样,当你有:
gcc -o test main.o libprintf.a
要处理的第一个目标文件是main.o
,其中注明了未解析的符号printf
,下一个要处理的是libprintf.a
,链接器可以从中解析printf
{{ 1}}。最终处理libc
时,printf
已经解决,因此printf
中libc
的实例未被使用。
与.o文件链接时:
gcc -o test main.o printf.o
libc
库再次被视为在命令行末尾指定,因此printf
符号从定义的第一个(从左到右)对象文件中解析它
对于两个libprintf.so
个案例,libc
库再次被视为在命令行末尾指定它。与静态库案例的不同之处在于*.so
库的从左到右排序决定了运行时动态符号搜索顺序。由于此订单在隐式libprintf.so
之前有libc.so
,因此会使用printf
中libprintf.so
的版本。
gcc -o test libprintf.so main.o
gcc -o test main.o libprintf.so
作为额外的实验,您可以尝试:
gcc -o test main.o -lc libprintf.so
这应该显示printf
使用的libc.so
版本,而不是libprintf.so
,因为-lc
按照从左到右的顺序出现在libprintf.so
之前。