Dynamic - shared libraries — .so - .dll, dynamic linking, PIC
WHY do shared libraries exist?
The three reasons dynamic linking won:
- Disk + RAM savings. One copy of
libc(~2 MB) shared by 200 processes instead of 200 copies. The OS maps the same physical pages into every process — but only the read-only code pages, not the writable data. - Update without recompiling. Patch a security bug in
libssl.so; every program picks it up on next launch. With static linking you'd relink the whole world. - Plugin architecture.
dlopen()/LoadLibrary()let a program load code it didn't know about at compile time.
WHAT is Position-Independent Code (PIC)?
HOW does PIC reach global data and functions?
Relative addressing is easy for internal jumps. The hard part is external symbols (a function in another library, or a global variable). Two tables solve this:

HOW dynamic linking happens — step by step
Derivation: why the code page must stay constant
Flashcards
What is the one-line difference between static and dynamic linking?
.so/.dll at run time.Why must shared-library code be position-independent?
What flag compiles PIC in GCC/Clang?
-fPIC (and -shared to produce the .so).What does the GOT store and why is it writable?
What is the PLT and what is "lazy binding"?
Where does the per-process absolute address actually live in a PIC library?
On Windows, what plays the role of the GOT?
Why can dynamic linking be faster for the whole system despite startup cost?
What program performs dynamic linking at startup on Linux?
ld-linux.so, named as the executable's interpreter.Why does link-time success not guarantee run-time loading?
.so file in the search paths.Recall Feynman: explain to a 12-year-old
Imagine 30 kids all need the same recipe book. Instead of photocopying it 30 times (wasting paper = static linking), the school keeps one book in the library and every kid just remembers "go look it up in the library" (dynamic linking). But the kids' classrooms are in different parts of the building, so the book can't say "turn left at room 12" (that depends where you are). Instead it says "turn left 2 doors from where you're standing" — directions that work from anywhere. Those self-relative directions are PIC. And each kid keeps a little sticky note (the GOT) with the exact page numbers filled in just for them.
Connections
- Static libraries — .a .lib — the alternative; trade-offs in size, updatability, page cache.
- The Linker — symbol resolution & relocation — relocations are what fill the GOT.
- Virtual Memory & mmap — shared read-only pages are the mechanism behind RAM savings.
- ASLR & Security — PIC also enables address randomization of libraries (and PIE executables).
- dlopen and Plugin Architectures — run-time loading of unknown-at-compile-time code.
- ELF and PE file formats —
DT_NEEDED, GOT/PLT sections vs Windows IAT.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, shared library ka pura idea simple hai: ek hi libc.so ya libfoo.so file disk pe hoti hai, aur 200 programs us same file ko use karte hain. Static linking mein library ka code seedha executable ke andar copy ho jaata hai — binary mota ho jaata hai aur har program apni alag copy carry karta hai. Dynamic linking mein executable sirf ek "promise" rakhta hai: "mujhe printf chahiye, run time pe dhoond lena." Fayda? RAM aur disk bachti hai (OS same physical pages sab processes mein map kar deta hai), aur agar library mein bug fix karna ho to bas .so update karo — saare programs automatically naya code le lete hain.
Ab asli twist: PIC (Position-Independent Code). Same library alag-alag process mein alag-alag virtual address pe load ho sakti hai. Agar code mein koi absolute address hardcode hota (jaise "printf 0x7f0000 pe hai"), to wo ek process mein sahi, dusre mein galat ho jaata. Isliye PIC code sirf relative addressing use karta hai — "current instruction se itne offset pe." Compile karte waqt -fPIC flag isi liye lagta hai. Logic chain yaad rakho: shared code page ke bytes sab process mein same hone chahiye → koi per-process value code mein nahi reh sakti → wo address ek alag writable data table (GOT) mein jaata hai.
GOT aur PLT do tables hain. GOT (Global Offset Table) ek writable data page hai jisme loader real addresses bharta hai, har process ke liye alag. PLT (Procedure Linkage Table) chhote stubs hain jo "lazy binding" karte hain — function ka pehla call hone par hi dynamic linker (ld-linux.so) us function ka address dhoond ke GOT mein likhta hai; baad ke calls seedhe GOT se jump kar jaate hain. Isse startup fast rehta hai kyunki sab functions ek saath resolve nahi karne padte.
Ek practical point: gcc app.o -lfoo compile ho jaana matlab program chalega bhi, ye guarantee nahi. Link time pe sirf symbol exist karta hai ye check hota hai. Run time pe ld-linux ko file physically dhoondhni padti hai (/usr/lib, LD_LIBRARY_PATH, ldconfig cache mein). Isiliye "error while loading shared libraries" tab aata hai jab .so move ho gayi ho. Windows mein same concept hai bas naam alag — .dll, IAT (Import Address Table) GOT jaisa, aur exports explicitly __declspec(dllexport) se mark karne padte hain.