简体   繁体   中英

Linking functions with LD_PRELOAD at runtime

I am writing a lib that intercepts the calls to malloc and free at runtime by running the program with LD_PRELOAD=mylib myexe .

The calls to malloc and free are intercept fine. My problem is that there's another function in mylib that I also want intercepted when LD_PRELOAD is used and I cannot figure out why it doesn't 'just work' like the calls to malloc and free .

In mylib.c:

void* malloc(size_t s)
{
    return doMyMalloc();
}

void free(void* p)
{
    doMyFree(p);
}

void otherThing(size_t)
{
    doThing();
}

In myexe.cpp:

#include <malloc.h>

extern "C" void otherThing(size_t);  // Compile with -Wl,--unresolved-symbols=ignore-all

int main(int argc, char* argv[])
{
    void* x = malloc(1000);   // Successfully intercepted.
    free(x);  // Successfully intercepted.
    otherThing(1);  // Segfault.
}

One way I have managed to get it to work is by doing:

typedef void (*FUNC)(size_t);
FUNC otherThing = NULL;

int main(int argc, char* argv[])
{
    otherThing = (FUNC)dlsym(RTLD_NEXT, "otherThing");
    otherThing(1);  // Successfully calls mylib's otherThing().
}

but I don't want to write all this code; I don't have to do it for malloc and free . It's ok if the program crashes if the LD_PRELOAD prefix is missing.

I feel like you're applying a single solution ( LD_PRELOAD ) to solve two different problems. First, you want to patch malloc() and free() . You've got that working--great. Next, you want to have a runtime "plug-in" system where you don't link against any library at build time, but only do so at runtime. This is typically done using dlopen() and dlsym() , and I recommend you use those.

The idea is that you don't want to specify a particular implementation of otherThing() at build time, but you do need to have some implementation at runtime (or you rightly expect to crash). So let's be explicit about it and use dlsym() to resolve the function name at runtime, of course with error detection in case it's not found.

As for where to define otherThing() , it can be in a totally separate file given to dlopen() , or in mylib (in which case pass NULL as the filename to dlopen() ).

It's a bit of a gotcha. There are several posts relating to this on the internet, but I'll try to break it down to 'getting it to work'.

If this is under Linux, then what has happened is that the app has been compiled to not be able to use the external symbol. The quickest solution is to add the same compilation flags to the main application as are used in the library ie add the -fPIC flag to the compilation of the main application, just like it is done for the library.

Rather than using the -Wl,--unresolved-symbols=ignore-all flag, you should be using the __attribute__ ((weak)) for the function, like:

extern "C" void otherThing(size_t) __attribute__ ((weak);

And checking it for NULL at run-time, which will allow you to determine if it's been set or not.

By compiling the main application in the same way as a .so , you are implicitly allowing it to be used itself as a target for LD_PRELOAD as, by the manual page:

LD_PRELOAD

A list of additional, user-specified, ELF shared libraries to be loaded before all others. The items of the list can be separated by spaces or colons. This can be used to selectively override functions in other shared libraries .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM