Linker and Libraries Guide

Loading Additional Objects

The previous sections have described how the runtime linker initializes a process from the dynamic executable and its dependencies as they were defined during the link-editing of each module. The runtime linker also provides an additional level of flexibility by allowing you to introduce new objects during process initialization.

The environment variable LD_PRELOAD can be initialized to a shared object or relocatable object filename, or a string of filenames separated by white space. These objects are mapped after the dynamic executable and before any dependencies, and are assigned world search scope, and global symbol visibility (see "Symbol Lookup"). For example:


$ LD_PRELOAD=./newstuff.so.1 prog

Here, the dynamic executable prog is mapped, followed by the shared object newstuff.so.1, and then by the dependencies defined within prog. The order in which these objects are processed can be displayed using ldd(1):


$ LD_PRELOAD=./newstuff.so.1 ldd prog
        ./newstuff.so.1 => ./newstuff.so
        libc.so.1 =>     /usr/lib/libc.so.1

Another example is:


$ LD_PRELOAD="./foo.o ./bar.o" prog

Here the preloading is a little more complex and time consuming. 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 exactly 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):


$ LD_PRELOAD="./foo.o ./bar.o" ldd prog
        ./foo.o =>       ./foo.o
        ./bar.o =>       ./bar.o
        libc.so.1 =>     /usr/lib/libc.so.1

These mechanisms of inserting an object after a dynamic executable take the concept of interposition introduced in "Interposition" to another level. Using these mechanisms, it is possible to experiment with a new implementation of a function that resides in a standard shared object. By preloading an object containing this function, it will interpose on the original. Thus the old 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. Here the intention is to interpose the new symbol on the original, allowing the new function to carry out some additional processing, while still having it call through to the original function. This mechanism requires that either a symbol alias that is to be associated with the original function (see "Simple Resolutions") or the ability to look up the original symbol's address (see "Using Interposition").