gccshared-librariessharedlddld-preload

lib specified by LD_PRELOAD can not be loaded


I met some trouble when using LD_PRELOAD to load my so.

The steps are as following:

  1. libtest.c:

    void fun()
    {
        return 
    }
    
  2. gcc -o libtest.so libtest.c -fPIC --shared

  3. export LD_PRELOAD=pwd/libtest.so

  4. main.c

    extern void fun(); void main() { fun() }

  5. gcc -o main -L. main.c -ltest

  6. Then ldd main

    ldd main linux-vdso.so.1=>(0x00007ffff7ffd000) /home/shiyanlou/Code/libtest.so(0x00007ffff7df9000) libtest.so=>not found libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6 (0x00007ffffa29000) /lib64/ld-linux-x86-64.so.2 (0x0000555555554000)

  7. execute main ./main it promotes: error while loading shared library:libtest.so. cannot open shared object file:No such file or directory.

I wonder that why it prompts that libtest.so cannot be found After I exported LD_PRELOAD variable. However, I also tried to use LD_PRELOAD to specify a different shared lib(not "libc.so") to inject malloc function, it works! Why LD_PRELOAD only works for the shared lib that was not used when linking???


Solution

  • You need to create 2 versions of the *.so. One which has default behavior and is loaded and hard linked via "-ltest".

    Now build your default libtest.so and prove with nm -B the symbol you are expecting to intercept is dynamically linked.

    Now build main.c into main.o, then check main.o with nm to also see it has an extern unsatisfied linkage requirement on the symbol.

    Now link ./main with main.o and libtest.so and then run it. The ./main needs to run with this copy by default, demonstrate the default behavior and also show the correct path to the correct DSO via ldd command.

    ...

    Now you take the step to create the LD_PRELOAD version.

    You shall call this libtest2.so. You do not use the -ltest2

    The point is that whoever built ./main does not know about libtest2.so at all, there is no hard linkage dependency.

    libtest2.so has alternative behavior, like make foo() returns a different string/number) and the goal now is to intercept this 2nd version at runtime, so the 1st version is not called by default (or at all). By using the LD_PRELOAD environment.

    LD_PRELOAD=./libtest2.so ./main

    ...

    Good luck.