Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When we are supposed to use RTLD_DEEPBIND?

Tags:

c++

c

gcc

dlopen

I was trying the issue mentioned at link: https://sourceware.org/ml/libc-alpha/2009-06/msg00168.html

I did some modification in the code as mentioned below:

>> 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)();
  }

Compiling the above files:

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 sees duplicate as: m

main sees duplicate address as: 600ba0

dynamic sees duplicate from libdep as: d

dynamic sees duplicate address as: 5f4fb868

libdep sees duplicate as: m

libdep sees duplicate address as: 600ba0

but libdep sees duplicate from main as: m

See that the same variable has different addresses. And if we remove the RTLD_DEEPBIND from the main.c, the output is as expected.

main sees duplicate as: m

main sees duplicate address as: 600ba0

dynamic sees duplicate from libdep as: d

dynamic sees duplicate address as: 600ba0

libdep sees duplicate as: d

libdep sees duplicate address as: 600ba0

but libdep sees duplicate from main as: d

So My questions are:

When we have the need to use RTLD_DEEPBIND?

How come dynamic.so has different address of duplicate variable when it didn't even had the definition of variable d?

( I tried on gcc 4.2.2 and gcc 4.8.2)

like image 578
Ritesh Avatar asked Dec 03 '15 18:12

Ritesh


Video Answer


1 Answers

You should use RTLD_DEEPBIND when you want to ensure that symbols looked up in the loaded library start within the library, and its dependencies before looking up the symbol in the global namespace.

This allows you to have the same named symbol being used in the library as might be available in the global namespace because of another library carrying the same definition; which may be wrong, or cause problems.

An example of a reason to use it is mentioned on the 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.

As to the second question - how come we see a different address of the duplicate - well that's a wonderful feature of you building the main application without the -fPIC option. If we use readelf -r on the main application it has a line reading:

000000600d08  001000000005 R_X86_64_COPY     0000000000600d08 duplicate + 0

Note that this has _COPY at the end. This means that when the symbol is found in libdep.so, it gets copied into the initial data segment of the main executable at that address. Then the reference to duplicate in libdep.so is looked up and it points to the copy of the symbol that's in the main executable.

The definition in libdep.so looks like:

0000002009b8  000e00000006 R_X86_64_GLOB_DAT 00000000002009f8 duplicate + 0

i.e. GLOB_DAT - global data.

When you load the dynamic.so, it has it's own request for the symbol. Because you use RTLD_DEEPBIND this definition is looked up in the dependencies of this library first, before looking in the main executable. As a result, it finds and uses the exposed GLOB_DAT from libdep.so and not the exposed data from a.out.

This is directly caused by linking to libdep.so as part of the compilation of dynamic.so. If you hadn't linked to it, then you would see the symbol with the other address - i.e. the copy in the main exe.

like image 103
Petesh Avatar answered Oct 23 '22 12:10

Petesh