Linker and Libraries Guide

Dependency Ordering

In most of the examples in this document, dependencies of dynamic executables and shared objects are portrayed as unique and relatively simple (the breadth-first ordering of dependent shared objects is described in "Locating Shared Object Dependencies"). From these examples, the ordering of shared objects as they are brought into the process address space might seem very intuitive and predictable.

However, when dynamic executables and shared objects have dependencies on the same common shared objects, the order in which the objects are processed can become less predictable.

For example, assume a shared object developer generates libfoo.so.1 with the following dependencies:


$ ldd libfoo.so.1
        libA.so.1 =>     ./libA.so.1
        libB.so.1 =>     ./libB.so.1
        libC.so.1 =>     ./libC.so.1

If you create a dynamic executable, prog, using this shared object, and also define an explicit dependency on libC.so.1, then the resulting shared object order will be:


$ cc -o prog main.c -R. -L. -lC -lfoo
$ ldd prog
        libC.so.1 =>     ./libC.so.1
        libfoo.so.1 =>   ./libfoo.so.1
        libA.so.1 =>     ./libA.so.1
        libB.so.1 =>     ./libB.so.1

Therefore, had the developer of the shared object libfoo.so.1 placed a requirement on the order of processing of its dependencies, this requirement will be compromised by the construction of the dynamic executable prog.

Developers who place special emphasis on symbol interposition (see "Symbol Lookup", "Symbol Lookup" and "Using Interposition") and .init section processing (see "Initialization and Termination Routines") should be aware of this potential change in shared object processing order.