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

When we are supposed to use RTLD_DEEPBIND?

我正在尝试 link 中提到的问题: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: %c\n", duplicate);
    printf("libdep sees duplicate address as: %x\n", &duplicate);
    return duplicate;
}
--------------------------------------------------------------------------------------

>> Cat  dynamic.c

#include <stdio.h>

  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 <stdio.h>
  #include <dlfcn.h>
  #include <stdlib.h>

  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

dynamic 从 libdep 中看到重复项:d

动态看到重复地址为:5f4fb868

libdep 认为重复为:m

libdep 将重复地址视为:600ba0

但 libdep 从 main 中看到重复项:m

看到同一个变量有不同的地址。如果我们从 main.c 中删除 RTLD_DEEPBIND,则输出符合预期。

main 认为重复为:m

main 看到重复地址为:600ba0

dynamic 从 libdep 中看到重复项:d

动态将重复地址视为:600ba0

libdep 认为重复为:d

libdep 将重复地址视为:600ba0

但 libdep 从 main 中看到重复项:d

所以我的问题是:

什么时候我们有需要使用RTLD_DEEPBIND?

为什么dynamic.so连变量d的定义都没有,却有不同的重复变量地址?

(我试过 gcc 4.2.2 和 gcc 4.8.2)

如果要确保在加载的库中查找的符号在全局命名空间中查找符号之前在库及其依赖项中启动,则应使用 RTLD_DEEPBIND

这允许您在库中使用与全局命名空间中可用的相同命名符号,因为另一个库带有相同的定义;这可能是错误的,或导致问题。

intel shared math functions page

中提到了使用它的原因示例

When one creates a shared library on Linux* that links in the Intel runtime libraries statically (for example, using the -static-intel option), the expectation is that the application will run the optimized version of functions from the Intel-provided libraries, which are statically linked to the shared library. For example, it is expected that calls to math functions like cos() resolve to libimf, the Intel-provided math library which contains optimized math functions. On Linux, the default behavior is to resolve the symbol to the GNU libm version of these routines.

关于第二个问题 - 我们怎么会看到重复的不同地址 - 这是你构建主应用程序的一个很棒的功能 没有 -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

GLOB_DAT - 全局数据。

当您加载 dynamic.so 时,它有自己的符号请求。因为你使用 RTLD_DEEPBIND 这个定义首先在这个库的依赖项中查找,然后在主可执行文件中查找。因此,它找到并使用 libdep.so 中公开的 GLOB_DAT 而不是 a.out.

中公开的数据

这是 直接 由于链接到 libdep.so 作为编译 dynamic.so 的一部分造成的。如果您没有链接到它,那么您会看到带有其他地址的符号 - 即主 exe 中的副本。