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