advancedLinking
What does dynamic linking buy you, and what does it cost?
Whether the candidate can argue both directions. Most people have one strong opinion here; the discriminator is whether they can state the case against their own position and name a concrete failure it causes.
What a strong answer covers
- It buys deferred binding. The shared object is resolved at load time, or lazily at first call, which means one copy of a library on disk and in memory across processes, security updates without relinking every consumer, plugins loadable at run time, and a smaller shipped artifact.
- It costs determinism. What you tested is not necessarily what runs: resolution depends on the search path, on link order, on version scripts, on preloading and on interposition, so a symbol can bind to a different definition on the deployment machine than on yours. Startup does real work — relocation processing and symbol lookup — which is why large dynamically linked programs start measurably slower. Calls go through an indirection table, so cross-library calls are slightly more expensive and, more importantly, cannot be inlined; the whole-program view a static link or LTO would have had is gone.
- And it produces its own failure class: the shared object is missing, or present at a different version whose ABI moved, and the program fails at load with a message about a symbol nobody in the team has heard of. Symbol versioning and
SONAMEexist to make that failure loud rather than silent, but only when the library author used them. - Static linking inverts all of it: reproducible, fast to start, fully optimizable across the whole program, and a bigger binary that must be rebuilt and redeployed for every dependency fix. Which is why containers, which already ship the whole userland, made static linking attractive again for services, while operating-system components stayed dynamic.
✓ Green flags
- Names lazy binding through a PLT/GOT-style indirection and why it exists.
- Raises reproducibility and "what you tested is not what runs" as a first-class cost.
- Knows dynamic calls block inlining and cross-module optimization.
- Mentions symbol versioning or
SONAMEas the mechanism that makes breakage detectable. - Frames the container era as changing the trade rather than settling it.
✗ Red flags
- "Dynamic linking is always better because you can patch the library." True for a distribution, mostly irrelevant for a container image that is rebuilt anyway.
- "Static binaries are huge." They are larger; with dead-section stripping and LTO the difference is usually far smaller than assumed.
- "Dynamic linking has no runtime cost." Relocation processing at startup and an indirect call per cross-library call are both measurable.
- "Version conflicts are a packaging problem." They are an ABI problem that packaging tries to contain, and no packaging system prevents two libraries needing incompatible versions of a third.
Follow-up
Your program works locally and fails at startup in the container with an undefined symbol. Walk me through the diagnosis.
Implementation challenge
What to ask them to write or trace on a whiteboard.
Describe what happens on the first call to a lazily bound function: which tables are read, which are written, and what changes on the second call.