Last time I showed you how to override functions in shared libraries by creating your own shared library and preloading it via the LD_PRELOAD
environment variable. Today I'll show you how to call the original function from the overridden function.
First, let's review the code example that we used in the previous article. We had a program called prog.c
that used fopen
:
#include <stdio.h>
int main(void) {
printf("Calling the fopen() function...\n");
FILE *fd = fopen("test.txt", "r");
if (!fd) {
printf("fopen() returned NULL\n");
return 1;
}
printf("fopen() succeeded\n");
return 0;
}
Today let's write a shared library called myfopen.c
that overrides fopen
in prog.c
and calls the original fopen
from the C standard library:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
FILE *fopen(const char *path, const char *mode) {
printf("In our own fopen, opening %s\n", path);
FILE *(*original_fopen)(const char*, const char*);
original_fopen = dlsym(RTLD_NEXT, "fopen");
return (*original_fopen)(path, mode);
}
This shared library exports the fopen
function that prints the path and then uses dlsym
with the RTLD_NEXT
pseudohandle to find the original fopen
function.
We must define the _GNU_SOURCE feature macro in order to get the RTLD_NEXT
definition from <dlfcn.h>
. What RTLD_NEXT
does is it finds the next occurrence of a function in the search order after the current library.
We can compile this shared library this way:
gcc -Wall -fPIC -shared -o myfopen.so myfopen.c -ldl
When we preload it and run prog
we get the following output:
$ LD_PRELOAD=./myfopen.so ./prog Calling the fopen() function... In our own fopen, opening test.txt fopen() succeeded
It prints the filename of the file we're opening and successfully opens it.
This is really useful if you need to change how a part of a program works or do some advanced debugging.
Next time we'll look at how LD_PRELOAD is implemented. Stay tuned!