Restricting symbols in a Linux static library Restricting symbols in a Linux static library linux linux

Restricting symbols in a Linux static library


I don't believe GNU ld has any such options; Ulrich must have meant objcopy, which has many such options: --localize-hidden, --localize-symbol=symbolname, --localize-symbols=filename.

The --localize-hidden in particular allows one to have a very fine control over which symbols are exposed. Consider:

int foo() { return 42; }int __attribute__((visibility("hidden"))) bar() { return 24; }gcc -c foo.cnm foo.o000000000000000b T bar0000000000000000 T fooobjcopy --localize-hidden foo.o bar.onm bar.o000000000000000b t bar0000000000000000 T foo

So bar() is no longer exported from the object (even though it is still present and usable for debugging). You could also remove bar() all together with objcopy --strip-unneeded.


Static libraries can not do what you want for code compiled with either GCC 3.x or 4.x.

If you can use shared objects (libraries), the GNU linker does what you need with a feature called a version script. This is usually used to provide version-specific entry points, but the degenerate case just distinguishes between public and private symbols without any versioning. A version script is specified with the --version-script= command line option to ld.

The contents of a version script that makes the entry points foo and bar public and hides all other interfaces:

{ global: foo; bar; local: *; };

See the ld doc at: http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

I'm a big advocate of shared libraries, and this ability to limit the visibility of globals is one their great virtues.

A document that provides more of the advantages of shared objects, but written for Solaris (by Greg Nakhimovsky of happy memory), is at http://developers.sun.com/solaris/articles/linker_mapfiles.html

I hope this helps.


The merits of this answer will depend on why you're using static libraries. If it's to allow the linker to drop unused objects later then I have little to add. If it's for the purpose of organisation - minimising the number of objects that have to be passed around to link applications - this extension of Employed Russian's answer may be of use.

At compile time, the visibility of all symbols within a compilation unit can be set using:

-fvisibility=hidden-fvisibility=default

This implies one can compile a single file "interface.c" with default visibility and a larger number of implementation files with hidden visibility, without annotating the source. A relocatable link will then produce a single object file where the non-api functions are "hidden":

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

The combined object file can now be subjected to objcopy:

objcopy --localize-hidden relocatable.o mylibrary.o

Thus we have a single object file "library" or "module" which exposes only the intended API.


The above strategy interacts moderately well with link time optimisation. Compile with -flto and perform the relocatable link by passing -r to the linker via the compiler:

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

Use objcopy to localise the hidden symbols as before, then call the linker a final time to strip the local symbols and whatever other dead code it can find in the post-lto object. Sadly, relocatable.o is unlikely to have retained any lto related information:

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

Current implementations of lto appear to be active during the relocatable link stage. With lto on, the hidden=>local symbols were stripped by the final relocatable link. Without lto, the hidden=>local symbols survived the final relocatable link.

Future implementations of lto seem likely to preserve the required metadata through the relocatable link stage, but at present the outcome of the relocatable link appears to be a plain old object file.