2 minute read

Tldr; See recommendations at end.

Talk: https://youtu.be/_enXuIxuNV4

Covered topics:

  • 101 of linkers+loaders
  • Detailed comparison of linking on Linux/Windows (not MacOS)
  • Interposition (overriding a symbol in one binary from another)
  • Library search order
  • Position independent code (GOT)
  • Lazy/Delayed Loading
  • Symbol visibility
  • Recommendations for shared libraries on linux

Interposition
Two binaries (e.g. object files, libraries) define the same symbol, then by default the first one will be taken. Linux specific / Not possible in Windows!

Library search order
Scenario: Executable (exe) loads shared libs lib1, lib2, which load lib3,..,5. The exe tries to load function foo.
Search order is breadth-first, i.e. first looked in exe, then lib1, lib2, lib3, .., 5.
LD_PRELOAD Can be used to specify libraries to look into after exe, but before lib1.
-Bsymbolic Look at first in current lib (e.g. lib5 calls function foo, then look at first in lib5).

Position Independent Code
Simple function calls in shared libraries will not be inlined (for default visibility). ...
Implemented via global offset table GOT.

Lazy Loading
Useful for huge number of symbols. On linux enabled by default, windows needs specific flags.
Workings: The function call to a shared library's function has an indirection which gets filled in by the loaded on first call. After that the shared library's function address is plugged in.
Implemented via procedural lookup table PLT.

Symbol Visibility
Question: Which symbols should get exported?
On Windows: Only those which are marked __declspec(dllexport).
On Linux: By default all.
Linux visibilities -fvisibility=<default/protected/hidden>:

  • default: all symbols exported
  • protected: symbols visible, but not subjected to interposition
  • hidden: not exported
  • per symbol: __attribute__ ((visibility ("hidden")))

Recommendation for linux shared libraries:
Opt out of interposition via building with: -fvisibility=hidden, -Bsymbolics
Mark symbols to be exported via: __attribute__ ((visibility ("protected")))