Linker order – GCC-Collection of common programming errors

If any [static] library A depends on symbols defined in library B, then library A should appear first in the list supplied to the linker.

+- prog.o -----+   +- libA.a -----+   +- libB.a -----+   
|   U funcA  --|---|-> T funcA    |   |              |    U : undefined/used
|              |   |   U funcB  --|---|-> T funcB    |    T : defined
|   T main     |   |              |   |              |   
+--------------+   +--------------+   +--------------+

Must be linked as

gcc prog.o libA.a libB.a -o prog.x
       \___^  \___^

or, of course,

gcc prog.o -lA -lB -o prog.x

which leaves the compiler open to choose the dynamic libA.so and libB.so variant, if available.

Dynamic Libraries

There is no requirements on the linking order of object files or dynamic libraries, though. Of course, a program that contains undefined behavior or depends on unspecified behavior could be affected by that order. For example, if the order of constructor invocations depends on the link order of object files, and the program accesses objects across translation unit boundaries, then it may access a not yet constructed object – because its translated translation unit was linked after another object file, which contains the other, not yet constructed object. Those effects, however, show up in defect programs – a correct program should not depend on such order.

Symbol resolution for dynamic librarries

There are no requirements regarding symbol resolution that could be affected by the link order of dynamic libraries or object files. Runtime effects that depends on that link order, as in the example above, could happen, but should not affect valid programs. Programs should use the tools of the toolchain to make sure they behave correctly. For example GCC has the possibility to control when a constructor runs, and can thereby order the priority of constructor calls at the initialization time of objects.

The issue with Static Libraries

Anyway, static libraries are required to be linked in this order – otherwise, unresolved references will appear with GNU ld:

If any library A depends on symbols defined in library B, then library A should appear first in the list supplied to the linker

That can sometimes cause trouble in build-scripts that can be configured to link either way.

Resolving cyclic dependencies (with gnu linker)

The GNU linker has an option which causes it to resolve cyclic references between A and B:

-( archives -) or --start-group archives --end-group The archives should be a list of archive files. They may be either explicit file names, or -l options.

The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references are resolved.

Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.

Note that archives in that description refer to static libraries. I’ve taken it from the manpage of GNU ld (man ld).

Specific case with the standard libs

One occasion that could be useful is to link together the c runtime library with the gcc low-level support libraries. Here is what my gcc port uses to pass to the linker:

"-lgcc" "-lc" "-lsyscalls" "-lgcc"

Because functions in libgcc may refer to functions defined in the C library, but functions in the C library may refer to functions defined in libgcc as well (it contains such functions as floating point emulation code). Another way to solve that problem could have been to use the start-group and end-group mechanism.

Originally posted 2013-11-09 22:41:17.