我有一个简单的示例两文件程序,该程序在Linux上运行(为清楚起见,略过错误处理)。
这是main.c
#include <dlfcn.h>
#include <stdio.h>
int glo = 1;
void test(void)
{
printf ("This is the main program\n");
printf ("%p %d\n", (void*)&glo, glo);
}
int main(void)
{
test();
void* l = dlopen("./lib.so", RTLD_NOW);
void (*fun)(void) = dlsym(l, "fun");
fun();
}
这是lib.c
#include <stdio.h>
int glo = 2;
void test(void)
{
printf ("This is the shared library\n");
printf ("%p %d\n", (void*)&glo, glo);
}
void fun(void)
{
test();
}
我以这种方式构建它们:
gcc -o main main.c -ldl
gcc -shared -fPIC -o lib.so lib.c
运行它们的结果是:
This is the main program
0x55af20d1e048 1
This is the shared library
0x7f6cb095d038 2
这意味着库未使用可执行文件中的符号,而是使用库本身中定义的符号。
我认为Linux上的动态加载不应该以这种方式工作。
dlopen
手册页上说
RTLD_DEEPBIND(自glibc 2.3.4起)
将符号的查找范围放在此共享库中的全局范围之前。这意味着自包含的对象将优先使用其自身的符号,而不是已加载的对象中包含的具有相同名称的全局符号。
默认当然不是RTLD_DEEPBIND
,这意味着已加载的共享对象应该更喜欢已加载的对象中包含的全局符号。这真的发生吗?我尝试调试动态链接过程:
LD_DEBUG=all ./main |& egrep glo\|test
....
30374: symbol=glo; lookup in file=./main [0]
30374: symbol=glo; lookup in file=/lib64/libdl.so.2 [0]
30374: symbol=glo; lookup in file=/lib64/libc.so.6 [0]
30374: symbol=glo; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
30374: symbol=glo; lookup in file=./lib.so [0]
30374: binding file ./lib.so [0] to ./lib.so [0]: normal symbol `glo'
30374: symbol=test; lookup in file=./main [0]
30374: symbol=test; lookup in file=/lib64/libdl.so.2 [0]
30374: symbol=test; lookup in file=/lib64/libc.so.6 [0]
30374: symbol=test; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
30374: symbol=test; lookup in file=./lib.so [0]
30374: binding file ./lib.so [0] to ./lib.so [0]: normal symbol `test'
看起来链接器在进入main
之前确实在lib.so
中查找了ip符号,但是由于某种原因找不到它们。
我想念什么?