Dlopen with higher priority than link time on linux

I am compiling a program on linux with gcc. The program itself links libc (and not much more) at build time, so ldd gives this output:

$ ldd myprogram
    linux-vdso.so.1 =>  (0x00007fffd31fe000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7a991c0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f7a99bba000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7a98fbb000)

      

During the execution of this program, the dlopen () s B library, which depends on the A library, which, of course, is loaded before returning. Exports the re_exec function that B calls (B is linked to A). libc also exports the re_exec function. readelf output:

$ readelf -as A.so | grep re_exec
 104: 00000000000044ff   803 FUNC    GLOBAL PROTECTED   11 re_exec
 469: 00000000000044ff   803 FUNC    GLOBAL PROTECTED   11 re_exec

$ readelf -as /lib/x86_64-linux-gnu/libc.so.6 | grep re_exec
 2165: 00000000000e4ae0    39 FUNC    WEAK   DEFAULT   12 re_exec@@GLIBC_2.2.5

      

The problem is that when B calls re_exec, re_exec inside libc is called, not re_exc inside A.

If I include LD_LIBRARY_PRELOAD = / path / to / A.so when I call the program, then everything works as expected: calling Bs re_exec correctly calls A, not libc.

Dlopen Calls Through RTLD_NOW | RTLD_GLOBAL. I tried with and without DEEPBIND and got the same behavior anyway.

I also tried dlopen () ing A directly before B, with or without DEEPBIND, which did not affect the behavior.

Question: is it possible to use dlopen A / B with a higher priority than the libraries that were included at the time of linking (libc, in this case)?

(please don't suggest renaming the call to something other than re_exec; not useful)

+3


source to share


1 answer


Well, you know, I cannot reproduce your error. Please have a look:

puts.c

:

#include <stdio.h>

int puts(const char* _s) {
    return printf("custom puts: %s\n", _s);
}

      

built with

cc -Wall -fPIC -c puts.c -o puts.o
cc -shared -o libputs.so -fPIC -Wl,-soname,libputs.so puts.o

      

foo.c

:

#include <stdio.h>

void foo() {
    puts("Hello, world! I'm foo!");
}

      

built with

cc -Wall -fPIC -c foo.c -o foo.o
cc -L`pwd` -shared -o libfoo.so -fPIC -Wl,-soname,libfoo.so foo.o -lputs

      



and rundl.c

:

#include <dlfcn.h>
#include <assert.h>
#include <stdio.h>

typedef void (*FooFunc)();

int main(void) {
    void *foolib = dlopen("./libfoo.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
    assert(foolib != NULL);
    FooFunc foo = (FooFunc)dlsym(foolib, "foo");
    assert(foo != NULL);
    foo();
    return 0;
}

      

built with

cc -c -Wall rundl.c -o rundl.o
cc -o rundl rundl.o -ldl

      

we can now run rundl

with LD_LIBRARY_PATH=$(pwd)

(this is necessary because it is libputs.so

not in ld.so

known paths, so libfoo.so

w / dlopen()

and Co cannot be loaded ):

alex@rhyme ~/tmp/dynlib $ LD_LIBRARY_PATH=`pwd` ./rundl
custom puts: Hello, world! I'm foo!
alex@rhyme ~/tmp/dynlib $ _

      

if we move libputs.so to a directory known ld.so

and (re) run ldconfig

to refresh the caches, then the code runs without any special environment variables:

alex@rhyme ~/tmp/dynlib $ ldd ./libfoo.so 
    linux-vdso.so.1 (0x00007fff48db8000)
    libputs.so => /usr/local/lib64/libputs.so (0x00007f8595450000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f85950a0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f8595888000)
alex@rhyme ~/tmp/dynlib $ ./rundl 
custom puts: Hello, world! I'm foo!

      

If the link libfoo.so

w / o -lputs

foo()

calls the standard puts()

from libc. What is it.

+1


source







All Articles