什么时候我们应该使用RTLD_DEEPBIND?

我正在尝试链接中提到的问题: https : //sourceware.org/ml/libc-alpha/2009-06/msg00168.html

我在代码中做了一些修改,如下所述:

>> Cat libdep.c #include  int 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选项的情况下构建主应用程序的一个很棒的function。 如果我们在主应用程序上使用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 

GLOB_DAT – 全球数据。

当你加载dynamic.so ,它有自己的符号请求。 因为您使用RTLD_DEEPBIND ,所以在查看主可执行文件之前,首先在此库的依赖项中RTLD_DEEPBIND此定义。 因此,它从libdep.so查找并使用公开的GLOB_DAT,而不是来自a.out的公开数据。

这是由于链接到libdep.so作为libdep.so编译的一部分而直接导致的。 如果你没有链接到它,那么你会看到带有另一个地址的符号 – 即主exe中的副本。