Recently I had a chance to play with
LD_PRELOAD for a bit, due to our recent
Huge Refactor (tm) at Nodejitsu.
LD_PRELOAD environment variable is a way of
loading a library before any other libraries are loaded.
For example, let’s write this short program in C:
Its output is obvious:
$ gcc puts.c -o puts $ ./puts Hello, world!
Now, as I mentioned before, with
LD_PRELOAD we can force our library to be
loaded before other libraries. This also affects
libc. That means that we can
Let’s compile this little library and try to override
dlsym(RTLD_NEXT, "puts"), we’re able to extract the original
function and call it with different arguments.
RTLD_NEXT is a pseudo-handle
which makes linker search for occurences of symbol in libraries loaded after
First problem we’re going to run into is the difference between how Mac OS X and other UNIX operating systems work.
To compile this library on Mac OS X execute:
To compile it on other operating systems, use:
Now that we compiled the library, let’s try overriding our
On Mac OS X:
$ export DYLD_FORCE_FLAT_NAMESPACE=1 $ export DYLD_INSERT_LIBRARIES=./puts-override.dylib $ ./puts
On other operating systems:
$ export LD_PRELOAD=./puts-override.so $ ./puts Hello, puts!
Now, the difference between compilation and usage come from the fact that Mac OS X uses a different linker than other systems. You can read more about OS X’s linker on its manual page.
That’s it for this blog post. If you have problems getting those instructions to work, shoot me a line!