Preloading Additional Objects
The runtime linker provides an additional level of flexibility by enabling you
to introduce new objects during process initialization by using the
environment variable LD_PRELOAD
. This environment variable can be initialized to a shared object
or relocatable object file name, or a string of file names separated by
white space. These objects are loaded after the executable and
before any dependencies. These objects are assigned
world search scope, and
global symbol visibility.
In the following example, the dynamic executable prog
is
loaded, followed by the shared object newstuff.so.1
.
The dependencies defined within prog
are then
loaded.
$ LD_PRELOAD=./newstuff.so.1 prog
The order in which these objects are processed can be displayed using
ldd
(1).
$ ldd -e LD_PRELOAD=./newstuff.so.1 prog
./newstuff.so.1 => ./newstuff.so
libc.so.1 => /lib/libc.so.1
In the following example, the preloading is a little more complex and time consuming.
$ LD_PRELOAD="./foo.o ./bar.o" prog
The runtime linker first link-edits the relocatable objects
foo.o
and bar.o
to
generate a shared object that is maintained in memory. This memory image is
then inserted between the dynamic executable and its dependencies in the
same manner as the shared object newstuff.so.1
was
preloaded in the previous example. Again, the order in which these objects
are processed can be displayed with
ldd
(1).
$ ldd -e LD_PRELOAD="./foo.o ./bar.o" ldd prog
./foo.o => ./foo.o
./bar.o => ./bar.o
libc.so.1 => /lib/libc.so.1
These mechanisms of inserting an object after an executable provide for interposition. You can use these mechanisms to experiment with a new implementation of a function that resides in a standard shared object. If you preload an object containing this function, the object interposes on the original. Thus, the original functionality can be completely hidden with the new preloaded version.
Another use of preloading is to augment a function that resides in a standard
shared object. The interposition of the new symbol on the original symbol
enables the new function to carry out additional processing. The new
function can also call through to the original function. This mechanism
typically obtains the original symbol's address using
dlsym
(3C) with the special handle
RTLD_NEXT
.