5

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

主程序

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

int main()
{
        printf("HELLO WROLD\n");
        return 0;
}

打印文件

#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 手册页不一致。所以为什么?

4

1 回答 1

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。当libc最终被处理时,printf已经被解析,因此不使用printfin的实例。libc

与 .o 文件链接时:

gcc -o test main.o printf.o

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

对于这两种libprintf.so情况,libc库再次被视为在命令行末尾指定。与静态库情况不同的是,库的从左到右的顺序*.so决定了运行时动态符号搜索的顺序。由于这个命令libprintf.so在隐式之前有,所以使用了inlibc.so的版本。printflibprintf.so

gcc -o test libprintf.so  main.o
gcc -o test main.o libprintf.so

作为附加实验,您可以尝试:

gcc -o test main.o -lc libprintf.so

这应该显示使用的版本,printflibc.so不是libprintf.so因为从左到右的顺序-lc出现在前面。libprintf.so

于 2012-05-14T16:27:11.797 回答