Binding Functions to LD_PRELOAD at Run Time

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

Calls to malloc and free are points of interception. My problem is that there is another function in mylib that I also want to intercept when using LD_PRELOAD , and I cannot understand why it does not work just like malloc and free calls.

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 of the ways that I was able to get it to work was to do:

 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 otherThing(). } 

but I do not want to write all this code; I do not need to do this for malloc and free . This is normal if the program crashes if the LD_PRELOAD prefix is ​​missing.

+4
source share
2 answers

I feel that you are applying one solution ( LD_PRELOAD ) to solve two different problems. First you want to schedule malloc() and free() . It works for you - great. Then you want to have a “plug-in” system in which you don’t bind to any library at build time, but only at runtime. This is usually done using dlopen() and dlsym() , and I recommend that you use them.

The idea is that you do not want to specify a specific implementation of otherThing() at build time, but you need to have some implementation at runtime (or you are rightly expecting a crash). Therefore, let's be frank about this and use dlsym() to resolve the name of the function at runtime, of course with error detection if it is not found.

As for the definition of otherThing() , it can be in a completely separate file specified in dlopen() , or in mylib (in this case, pass NULL as the file name to dlopen() ).

0
source

This is a bit like. There are several posts on the Internet related to this, but I will try to break it in order to “make it work”.

If it is under Linux, then it happened that the application was compiled so that it was not possible to use an external character. The quickest solution is to add the same compilation flags to the main application that are used in the library, that is, add the -fPIC flag to the compilation of the main application, just like the library does.

Instead of using the -Wl,--unresolved-symbols=ignore-all flag -Wl,--unresolved-symbols=ignore-all you should use __attribute__ ((weak)) for the function, for example:

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

And we check it for NULL at runtime, which allows you to determine whether it was installed or not.

By compiling the main application in the same way as .so , you implicitly allow it to use itself as the target for LD_PRELOAD , as on the manual page:

LD_PRELOAD

A list of additional, user-defined, shared ELF libraries is loaded in front of everyone else. List items can be separated by spaces or colons. This can be used to selectively override functions in other shared libraries .

0
source

All Articles