I have some C source file func1.c、func2.c、main.c and a C header file func1.h、func2.h as follows:
// func1.h
#ifndef _FUNC1_H
#define _FUNC1_H
void show(int* nums, int n);
#endif
// func1.c
#include "func1.h"
#include <stdio.h>
void show(int* nums, int n)
{
int i;
for(i = 0; i < n; i++)
{
printf("%d ", nums[i]);
}
printf("\n");
}
// func2.h
#ifndef _FUNC2_H
#define _FUNC2_H
void show2(void* nums, int len);
#endif
// func2.c
#include "func1.h"
void show2(void* nums, int len)
{
int* array = (int*)nums;
show(array, len);
}
//main.c
#include <stdio.h>
#include <dlfcn.h>
typedef void (*SHOW2_FUNC)(void* nums, int len);
static void * handler = NULL;
void* get_func(const char* libname)
{
handler = dlopen(libname, RTLD_LAZY);
if (handler == NULL)
{
printf("open lib: %s error! \n", libname);
return NULL;
}
SHOW2_FUNC show_func = dlsym(handler, "show2");
if (show_func == NULL)
{
printf("can't find function: %s ! \n", "show2");
return NULL;
}
printf("find funcion successful, address is %p \n", show_func);
return show_func;
}
int main()
{
int nums[5] = {1, 2, 3, 4, 5};
SHOW2_FUNC pf_show = get_func("./libfunc2.so");
pf_show(nums, 5);
dlclose(handler);
return 0;
}
I use the following gcc command to compile func1.c,and I got static link library libfunc1.a
gcc -c func1.c -o func1.o
ar crv libfunc1.a func1.o
And then, I use the following gcc command to compile func2.c, and I got dynamic link library libfunc2.so
gcc -c func2.c -o func2.o
gcc func2.o -o libfunc2.so -shared -fPIC libfunc1.a
Finally, I use the following gcc command to compile main.c, and I got executable file main
gcc -o main main.c -ldl
Execute main, the results are as follows:
find funcion successful, address is 0x7fdadcde069a
1 2 3 4 5
The result of running the ldd libfunc2.so command is as follows:
linux-vdso.so.1 (0x00007fffd8e91000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd687be0000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd688200000)
But, if I use the following gcc command to compile func2.c. No errors were reported during compilation.
gcc -o libfunc2.so -shared -fPIC libfunc1.a func2.o # Place the file func2.o at the end
Execute main again, the results are as follows, and I got a run error.
find funcion successful, address is 0x7f6b577e05ba
./main: symbol lookup error: ./libfunc2.so: undefined symbol: show
The result of running the ldd libfunc2.so command is as follows:
statically linked
Bisides, I compile func1.c into a dynamic link library libfunc1.so, and use it to compile libfunc2.so. Compile commands are as follows:
gcc func1.c -o libfunc1.so -shared -fPIC
gcc -o libfunc2.so -shared -fPIC -L. -lfunc1 -Wl,-rpath=. func2.o
Execute main again, the results are as follows, and I got a run error.
find funcion successful, address is 0x7f6b577e05ba
./main: symbol lookup error: ./libfunc2.so: undefined symbol: show
Why would a different order lead to the above result? Why is there no error at compile time? Thank you for reading.
I created the files and used the following makefile with commands from your post:
all:
gcc -c func1.c -o func1.o
ar crv libfunc1.a func1.o
gcc -c func2.c -o func2.o
gcc func2.o -o libfunc2.so -shared -fPIC libfunc1.a
gcc -o main main.c -ldl
./main || :
ldd libfunc2.so
gcc -o libfunc2.so -shared -fPIC libfunc1.a func2.o
./main || :
ldd libfunc2.so
gcc func1.c -o libfunc1.so -shared -fPIC
gcc -o libfunc2.so -shared -fPIC -L. -lfunc1 -Wl,-rpath=. func2.o
./main || :
it results in the following output:
gcc -c func1.c -o func1.o
ar crv libfunc1.a func1.o
r - func1.o
gcc -c func2.c -o func2.o
gcc func2.o -o libfunc2.so -shared -fPIC libfunc1.a
gcc -o main main.c -ldl
./main || :
find funcion successful, address is 0x7fb8d951c129
1 2 3 4 5
ldd libfunc2.so
linux-vdso.so.1 (0x00007ffe1a7e7000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f24dab42000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f24dad72000)
gcc -o libfunc2.so -shared -fPIC libfunc1.a func2.o
./main || :
find funcion successful, address is 0x7f9a49030109
./main: symbol lookup error: ./libfunc2.so: undefined symbol: show
ldd libfunc2.so
linux-vdso.so.1 (0x00007ffc92996000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f245acd8000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f245af08000)
gcc func1.c -o libfunc1.so -shared -fPIC
gcc -o libfunc2.so -shared -fPIC -L. -lfunc1 -Wl,-rpath=. func2.o
./main || :
find funcion successful, address is 0x7fab12301109
1 2 3 4 5
I am running on ArchLinux gcc13.2.1 ld.so2.38.
gcc -o libfunc2.so -shared -fPIC libfunc1.a func2.o # Place the file func2.o at the endExecute main again, the results are as follows, and I got a run error.
find funcion successful, address is 0x7f6b577e05ba ./main: symbol lookup error: ./libfunc2.so: undefined symbol: show
Yes. If you take a look at libfunc2.so, you will see that:
$ nm ./libfunc2.so
.....
U show
0000000000001109 T show2
0000000000004010 d __TMC_END__
Symbol show is undefined. Why is that? Because from https://man7.org/linux/man-pages/man1/ld.1.html :
The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.
In short, only used symbols from archive are used at the time they are encountered. So func2.o has to be before libfunc1.a on the command line. Or, use --whole-archive option. See also https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html .
The result of running the ldd libfunc2.so command is as follows:
statically linked
I believe you made an error here, I am not able to reproduce. For me, the output at this point is:
ldd libfunc2.so
linux-vdso.so.1 (0x00007ffdc39f3000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6613201000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f6613431000)
gcc func1.c -o libfunc1.so -shared -fPIC gcc -o libfunc2.so -shared -fPIC -L. -lfunc1 -Wl,-rpath=. func2.oExecute main again, the results are as follows, and I got a run error.
find funcion successful, address is 0x7f6b577e05ba ./main: symbol lookup error: ./libfunc2.so: undefined symbol: show
Once again, I am not able to reproduce. For me, at this stage, the executable links using RPATH=. with libfunc1.so, like the following:
$ LD_DEBUG=all ./main 2>&1 | grep show
63682: symbol=show2; lookup in file=./libfunc2.so [0]
63682: binding file ./libfunc2.so [0] to ./libfunc2.so [0]: normal symbol `show2'
63682: symbol=show; lookup in file=./main [0]
63682: symbol=show; lookup in file=/usr/lib/libc.so.6 [0]
63682: symbol=show; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
63682: symbol=show; lookup in file=./libfunc2.so [0]
63682: symbol=show; lookup in file=./libfunc1.so [0]
63682: binding file ./libfunc2.so [0] to ./libfunc1.so [0]: normal symbol `show'
Why would a different order lead to the above result?
Because linker searcher for symbols in linked archives in order of the command line parameters.
Why is there no error at compile time?
The magic of shared libraries is that you they are resolved at runtime, not compile time. So no compile time errors. You can ignore unresolved symbols - it's just a sanity check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With