Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

some questions about search order of GCC linker

I have some questions about gcc link order. GCC man says linker search symbols from left to right without repeatly search by default. Here is my test:

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

From the result, we can see the order of .o and .o, .o and .so make no difference, only order of .o and .a has the effect. But that is inconsistant with gcc man page. So why?

like image 578
D3Hunter Avatar asked May 14 '12 14:05

D3Hunter


1 Answers

gcc does indeed process the object files from left to right. When you have

gcc -o test libprintf.a main.o

The first object file gcc sees is libprintf.a. There are no unresolved symbols for the output object at this point, so nothing from libprintf.a is used/needed. Next, main.o is processed, the linker makes a note of the fact that printf is unresolved, and then proceeds to process the implicit libraries where it is able to resolve the printf symbol that was unresolved in main.o.

Likewise, when you have:

gcc -o test main.o libprintf.a 

The first object file to be processed is main.o, where the unresolved symbol printf is noted, the next to be processed is libprintf.a from which the linker is able to resolve printf. When libc is eventually processed, printf is already resolved so the instance of printf in libc is not used.

When linking with .o files:

gcc -o test main.o printf.o

The libc library is again treated as if it was specified at the end of the command line, so the printf symbol is resolved from the first (left-to-right) object file that defines it.

For both of the libprintf.so cases, the libc library is again treated as if it was specified at the end of the command line. What is different from the static library case is that the left-to-right ordering of the *.so libraries determines the run-time dynamic symbol search order. Since this order has libprintf.so before the implicit libc.so, the version of printf in libprintf.so is used.

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

As an additional experiment, you could try:

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

This should show the version of printf being used from libc.so instead of libprintf.so because -lc comes before libprintf.so in left-to-right order.

like image 67
Lance Richardson Avatar answered Nov 15 '22 10:11

Lance Richardson