Reputation: 143915
Suppose I want to completely take over the open() system call, maybe to wrap the actual syscall and perform some logging. One way to do this is to use LD_PRELOAD to load a (user-made) shared object library that takes over the open() entry point.
The user-made open() routine then obtains the pointer to the glibc function open()
by dlsym()
ing it, and calling it.
The solution proposed above is a dynamic solution, however. Suppose I want to link my own open()
wrapper statically. How would I do it? I guess the mechanism is the same, but I also guess there will be a symbol clash between the user-defined open()
and the libc open()
.
Please share any other techniques to achieve the same goal.
Upvotes: 32
Views: 18997
Reputation: 126488
For linux and GNU libc, the library has built-in support for intercepting and reimplementing any function in the library.
If you define you own version of ANY libc function, and link it before libc (so have it part of your executable, or in a library linked before -lc on the link command or even loaded with LD_PRELOAD
if libc is dynamically linke), it will be called instead of the libc version (even calls in other function in libc itself). You can then call the function with a __libc_
prefix to get the actual version in the library (though you will need to declare that symbol yourself.) For example:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
extern int __libc_open(const char *pathname, int flags, mode_t mode);
int open(const char *pathname, int flags, mode_t mode) {
return __libc_open(pathname, flags, mode);
}
Upvotes: 0
Reputation: 5393
You can use the wrap feature provided by ld
. From man ld
:
--wrap symbol
Use a wrapper function for symbol. Any undefined reference tosymbol
will be resolved to__wrap_symbol
.Any undefined reference to
__real_symbol
will be resolved tosymbol
.
So you just have to use the prefix __wrap_
for your wrapper function and __real_
when you want to call the real function. A simple example is:
malloc_wrapper.c
:
#include <stdio.h>
void *__real_malloc (size_t);
/* This function wraps the real malloc */
void * __wrap_malloc (size_t size)
{
void *lptr = __real_malloc(size);
printf("Malloc: %lu bytes @%p\n", size, lptr);
return lptr;
}
Test application testapp.c
:
#include <stdio.h>
#include <stdlib.h>
int main()
{
free(malloc(1024)); // malloc will resolve to __wrap_malloc
return 0;
}
Then compile the application:
gcc -c malloc_wrapper.c
gcc -c testapp.c
gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp
The output of the resulting application will be:
$ ./testapp
Malloc: 1024 bytes @0x20d8010
Upvotes: 63
Reputation: 27242
Symbols are resolved by the linker in the order you list them on the command line so if you listed your library before the standard library you'd have precidence. For gcc you'd need to specify
gcc <BLAH> -nodefaultlibs <BLAH BLAH> -lYOUR_LIB <OTHER_LIBS>
This way your libraries would be searched and found first.
Upvotes: 3