关于GCC链接器搜索顺序的一些问题

D3H*_*ter 5 linux linker gcc shared-libraries static-libraries

我对gcc链接顺序有一些疑问.GCC man表示链接器从左到右搜索符号,默认情况下不重复搜索.这是我的测试:

main.c中

#include <stdio.h>
#include <stdlib.h>

int main()
{
        printf("HELLO WROLD\n");
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

从结果中,我们可以看到.o和.o,.o和.so的顺序没有区别,只有.o和.a的顺序才有效.但这与gcc手册页不一致.所以为什么?

Lan*_*son 8

gcc确实从左到右处理目标文件.当你有

gcc -o test libprintf.a main.o
Run Code Online (Sandbox Code Playgroud)

gcc看到的第一个目标文件是libprintf.a.此时输出对象没有未解析的符号,因此libprintf.a不需要使用/需要任何符号.接下来,main.o处理后,链接器会记录printf未解析的事实,然后继续处理隐式库,以便能够解析printf未解析的符号in main.o.

同样,当你有:

gcc -o test main.o libprintf.a 
Run Code Online (Sandbox Code Playgroud)

要处理的第一个目标文件是main.o,在printf注明未解析的符号的情况下,要处理的下一个目标文件是libprintf.a链接器能够解析的printf.何时libc最终处理,printf已经解决,因此不使用printfin 的实例libc.

与.o文件链接时:

gcc -o test main.o printf.o
Run Code Online (Sandbox Code Playgroud)

libc库再次被视为在命令行的末尾指定它,因此printf符号从定义它的第一个(从左到右)目标文件中解析.

对于这两种libprintf.so情况,libc库再次被视为在命令行末尾指定了它.与静态库情况的不同之处在于,库的从左到右的顺序*.so决定了运行时动态符号搜索顺序.由于此订单libprintf.so在隐含之前libc.so,因此使用了printfin 的版本libprintf.so.

gcc -o test libprintf.so  main.o
gcc -o test main.o libprintf.so
Run Code Online (Sandbox Code Playgroud)

作为额外的实验,您可以尝试:

gcc -o test main.o -lc libprintf.so
Run Code Online (Sandbox Code Playgroud)

这应该显示的版本printf被使用libc.so,而不是libprintf.so因为-lc来之前libprintf.so在左到右的顺序.