Introduction
By default, the static linker (ld) makes all ELF symbols global in scope. This means it puts the symbols into the dynamic symbol table of the resulting binary such that other binary modules can access those symbols. The dynamic relocations that the dynamic linker performs during run-time are only necessary for the global (also known as external or exported) symbols. The static linker resolves references to local symbols (for example, names of static functions) statically when it links the binary.
Application performs better if the run-time linker (ld.so.1) has less number of relocations (relocations are expensive). It can be achieved by reducing the scope of some of the symbols i.e., by not exporting all the symbols or simply by not making all symbols global in scope. Export only those symbols that are need by external modules with SS9's (Sun Studio 9) compiler flag -xldscope=hidden & __declspec(dllexport | dllimport) specifiers
Advantages
1) -Kpic Vs -KPIC
We can take advantage of -Kpic (PIC = Position Independent Code) which is the fastest compared to -KPIC. -Kpis can handle only 2048 global symbols, but fast. Since we were reducing the global symbol count, most of the libraries can be compiled with -Kpic
The PIC-compiled code allows the linker to keep a read-only version of the text (code) segment for a given shared library. The dynamic linker can share this text segment among all running processes, referencing it at a given time
2) Less chance for name collisions with 3rd party libraries
Name collisions are hard to detect/bug. 3rd party libraries can create havoc when some of their symbol names coincide with those in the application. For example, if a third-party shared library uses a global symbol with the same name as a global symbol in one of the application's shared libraries, the symbol from the third-party library may interpose on yours and unintentionally change the functionality of your application without any warning
3) Improved performance
It lets the optimiser produce better code. PLT indirections (when a function call or variable access must be looked up via the Global Offset Table) can be completely avoided, thus substantially avoiding pipeline stalls on modern processors and thus much faster code. Furthermore when most of the symbols are bound locally, they can be safely elided (removed) completely through the entire shared object. This gives greater latitude especially to the inliner which no longer needs to keep an entry point around "just in case"
In summary: Application performs better due to the decreased size of the link maps and reduced number of page faults resulting from symbol scope reduction
4) Improved load times of shared libraries during run-time
5) Improved security
strip utility is not enough to hide the names of the application's routines and data items; stripping eliminates the local symbols but not the global symbols
Dynamically linked binaries (both executables and shared libraries) use two symbol tables: the static symbol table and the dynamic symbol table. The dynamic symbol table is used by the runtime linker. It has to be present even in stripped executables, or else the dynamic linker is not able to find the symbols it needs. The strip utility can only remove the static symbol table
By making most of the symbols of the application local in scope, the symbol information for such local symbols in a stripped binary is really gone and are not available at runtime; so no one can extract it
6) Reduced application binary sizes
More detailed explanation & examples are available at:
http://technopark02.blogspot.com/2004_09_01_technopark02_archive.html
References:
1) SS9 C++ user's guide
2) Article: "Enhancing Applications by Directing Linker Symbol Processing" by "Greg Nakhimovsky", Sun Microsystems, Inc.
3) Niall Douglas' "GCC Symbol Visibility Patch" release notes:
http://www.nedprod.com/programs/gccvisibility.html