Search code examples
linuxlinkershared-librariessymbolsld-preload

Switching Between More than Two Shared Libraries (LD_PRELOAD)


Suppose that there exists three shared libraries A.so, B.so and C.so, each having a function f(). I want to switch between each function f() under certain circumstances, determined at runtime. Using the LD_PRELOAD trick, I will execute the program p (i.e., the user of these libraries) as follows:

LD_PRELOAD=A.so:B.so:C.so ./p

f() in A.so will be the default. In that f() instance, I can access f() of B.so using dlsym(), as follows:

void f() // in A.so
{
...
    void *f_in_B = dlsym(RTLD_NEXT, "f");
...
}

How can I access the f() instance in C.so?


UPDATE:

Although yugr's answer works in the simple case, it has problems in more general conditions. I will shed some light on the problem by giving more details the current situation:

I need two different dynamic memory allocators and do not want to deal with internal implementation details of glibc malloc(),.... Put simply, I have two separate memory areas each with its own glibc. I use LD_PRELOAD to switch between the allocators based on some runtime condition. I used yugr's answer to load and access the secondary library.

Firstly, I called ptmalloc_init() in the secondary library to initialize malloc() data structures. I have also managed brk() calls at the OS system call level in such a way that each library has its own large brk() range and this avoids further conflicts.

The problem is that the solution works only at the application/glibc boundary. For example, when I use malloc() in the secondary library, it calls functions such as __default_morecore() in the primary library, internally, and these calls can not be captured by the LD_PRELOAD trick.

Why does this happen? I thought that the internal symbols of a library are set internally at the library compilation time, but, here, it seems that they use the symbols in the primary library of LD_PRELOAD. If the resolution is done by the linker, why these seemingly internal symbols are not captured by the LD_PRELOAD trick?

How can I fix the problem? Should I rename all the exported functions in the secondary library? Or the only feasible approach is to use a single library and delve into the implementation stuff?


Solution

  • You can dlopen each of the three libraries at startup to obtain their handles and use those to call dlsym(h, "f") to get particular implementations of f. If you don't know library names in advance you could use dl_iterate_phdr to obtain them (see this code for example).