我正在尝试链接中提到的问题:https://sourceware.org/ml/libc-alpha/2009-06/msg00168.html
我在代码中做了一些修改,如下所述:
>> Cat libdep.c #includeint duplicate = 'u'; int get_duplicate() { printf("libdep sees duplicate as: %c\n", duplicate); printf("libdep sees duplicate address as: %x\n", &duplicate); return duplicate; } -------------------------------------------------------------------------------------- >> Cat dynamic.c #include extern int duplicate; int run() { duplicate = 'd'; printf("dynamic sees duplicate from libdep as: %c\n", duplicate); printf("dynamic sees duplicate address as: %x\n", &duplicate); printf("but libdep sees duplicate from main as: %c\n", get_duplicate()); return 0; } ------------------------------------------------------------------------------------------------- Cat main.c #include #include #include extern int duplicate; int main() { void *h; int (*run)(); duplicate = 'm'; printf("main sees duplicate as: %c\n", duplicate); printf("main sees duplicate address as: %x\n", &duplicate); h = dlopen("./dynamic.so", RTLD_LAZY | RTLD_DEEPBIND); if (!h) abort(); run = dlsym(h, "run"); if (!run) abort(); (*run)(); }
编译上面的文件:
gcc -ggdb3 -shared -fPIC libdep.c -o libdep.so
gcc -ggdb3 -shared -fPIC dynamic.c -Wl,-rpath,.-L.-ldep -o dynamic.so
gcc -ggdb3 main.c -Wl,-rpath,.-L.-ldep -ldl
./a.out
main看起来像副本:m
main看到重复地址为:600ba0
动态从libdep看到副本为:d
dynamic将重复地址视为:5f4fb868
libdep将副本视为:m
libdep将重复地址视为:600ba0
但是libdep看到来自main的副本为:m
看到同一个变量有不同的地址.如果我们从main.c中删除RTLD_DEEPBIND,则输出符合预期.
main看起来像副本:m
main看到重复地址为:600ba0
动态从libdep看到副本为:d
dynamic将重复地址视为:600ba0
libdep将副本视为:d
libdep将重复地址视为:600ba0
但是libdep看到来自main的副本为:d
所以我的问题是:
当我们需要使用RTLD_DEEPBIND时?
为什么dynamic.so在没有变量d的定义时有不同的重复变量地址?
(我试过gcc 4.2.2和gcc 4.8.2)
RTLD_DEEPBIND
当你想要确保在加载的库中查找符号时,你应该使用它,并且在查找全局命名空间中的符号之前它是依赖关系.
这允许您在库中使用与在全局命名空间中可用的相同的命名符号,因为另一个库具有相同的定义; 这可能是错误的,或导致问题.
在intel共享数学函数页面上提到了使用它的原因的示例
当一个人在Linux*上创建一个静态链接在英特尔运行时库中的共享库(例如,使用-static-intel选项)时,期望应用程序将运行英特尔提供的库中的优化版本的函数,它们静态链接到共享库.例如,期望对诸如cos()之类的数学函数的调用解析为libimf,这是Intel提供的包含优化数学函数的数学库.在Linux上,默认行为是将符号解析为这些例程的GNU libm版本.
至于第二个问题-为什么我们看到重复的不同的地址-嗯,这是你构建的主要应用一个奇妙的功能,而不该-fPIC
选项.如果我们readelf -r
在主应用程序上使用它有一个行读数:
000000600d08 001000000005 R_X86_64_COPY 0000000000600d08 duplicate + 0
请注意,这已经_COPY
结束了.这意味着当找到符号时libdep.so
,它将被复制到该地址的主可执行文件的初始数据段中.然后查找对duplicate
in 的引用libdep.so
,它指向主可执行文件中的符号副本.
定义libdep.so
如下:
0000002009b8 000e00000006 R_X86_64_GLOB_DAT 00000000002009f8 duplicate + 0
即GLOB_DAT
- 全球数据.
加载时dynamic.so
,它有自己的符号请求.因为RTLD_DEEPBIND
在查看主可执行文件之前,首先在此库的依赖项中查找此定义.因此,它查找并使用公开的GLOB_DAT,libdep.so
而不是公开的数据a.out
.
这是直接由链接到libdep.so
编译的一部分引起的dynamic.so
.如果你没有链接到它,那么你会看到带有另一个地址的符号 - 即主exe中的副本.