5.5.17 · D2 · HinglishEmbedded Systems & Real-Time Software

Visual walkthroughLinker scripts — memory regions, sections (.text, .data, .bss)

3,195 words15 min read↑ Read in English

5.5.17 · D2 · Coding › Embedded Systems & Real-Time Software › Linker scripts — memory regions, sections (.text, .data, .bs

Shuru karne se pehle, teen plain-English words jo hum baar baar use karenge:

  • Address — memory ka ek ghar ka number. Chip mein storage ka har byte ek address rakhta hai. Hum inhe 0x08000000 ki tarah likhte hain (0x ka bas matlab hai "yeh ek hexadecimal number hai", jo ek base-16 counting system hai jo memory ke wiring ke saath neat align hota hai). Tum ise "ek bada number jo ek location ko naam deta hai" ki tarah padh sakte ho.
  • Flash — chip ki attic: power off hone par bhi apne contents yaad rakhti hai, lekin program chalte waqt ise sasta mein rewrite nahi kar sakte.
  • RAM — chip ki desk: read aur write karne mein fast, lekin power wapas aate hi bilkul blank garbage ho jaati hai.

Neeche ki poori kahani un do facts ko ek aisi variable ke liye reconcile karne ki hai jo starting value bhi yaad rakhe aur changeable bhi ho.


Step 1 — Do memories, do number lines

KYA. Hum chip ki memory ko do alag number lines ki tarah draw karte hain: Flash address 0x08000000 se start karta hai, RAM 0x20000000 se start karta hai. Har line numbered boxes (bytes) ki ek row hai.

KYUN. Linker scripts ke baare mein saari confusion is baat ko bhoolne se aati hai ki yeh silicon ke do physically alag chips hain jinke do unrelated address ranges hain. Agar hum inhe side by side kabhi nahi draw karte, to hum inhe mix up kar lenge. Is liye hum poori derivation ko pehle is picture par anchor karte hain.

PICTURE. Neeche ke do grey strips dekho. Blue strip (upar) Flash hai — notice karo ki iske numbers 0x08000000 se start hote hain. Green strip (neeche) RAM hai — iske numbers 0x20000000 se start hote hain. Yeh touch nahi karte. Inke beech ek bada gap hai; woh gap bas woh addresses hain jo chip use nahi karta.

To picture mein: Flash hai aur RAM hai .


Step 2 — int x = 5; ko kahan rehna chahiye? Ek contradiction

KYA. Hum apne ek variable ke baare mein do simple questions poochte hain aur discover karte hain ki woh opposite answers demand karte hain.

KYUN. Yahi contradiction hai jis wajah se linker scripts complicated hote hain. Agar hum contradiction feel nahi karte, to uske baad wala fix arbitrary magic lagta hai.

PICTURE. Do questions, do demands ki tarah draw kiye gaye jo x ko opposite directions mein kheench rahe hain:

  • Demand A (orange arrow → Flash): value 5 ko power-off ke baad bhi survive karna hai. RAM har power-up par wipe ho jaati hai, is liye number 5 sirf RAM mein store nahi ho sakta — use kahin non-volatile, yaani Flash mein record karna hoga.
  • Demand B (green arrow → RAM): program baad mein x = x + 1; karega. Tum runtime par Flash ko sasta mein nahi likh sakte. Is liye x ki live, changeable copy RAM mein rehni chahiye.

Step 3 — Do addresses ko naam dena: LMA aur VMA

KYA. Hum do addresses ko unke official names dete hain aur exact bytes draw karte hain.

KYUN. Data ko move karne se pehle cheezein naam karni padti hain. Yeh do names har real linker script mein aate hain, is liye hum inhe picture par earn karte hain, faith par nahi.

PICTURE. Single value 5 ko 4 bytes (int 4 bytes hai) ki tarah Flash mein uski LMA par dikhaya gaya hai, saath mein ek dotted "will be copied to" arrow uske future VMA in RAM ki taraf point karta hai. Abhi, power-on par, RAM boxes red hain — woh garbage hold karte hain.

  • LOADADDR(.data) ::: linker function jo Flash address report karta hai — LMA
  • ADDR(.data) ::: linker function jo RAM address report karta hai — VMA
  • ::: yahi inequality poora point hai. Code (.text) ke liye yeh do equal hote hain; initialized data ke liye yeh differ karte hain.

Step 4 — Har variable ko ek bucket mein sort karna (.text / .data / .bss)

KYA. Hum ek variable se sabhi par generalize karte hain. Tumhare program ka har piece exactly do yes/no questions ke basis par ek bucket mein jaata hai.

KYUN. Linker variables ko ek ek karke reason nahi kar sakta — woh hazaaron ko kuch sections mein group karta hai, phir har section ko ek block ki tarah place karta hai. Sorting rule samajhna matlab tum predict kar sakte ho ki koi bhi cheez kaun se section mein land karegi.

PICTURE. Ek decision tree: har item do questions ke through neeche flow hota hua teen boxes mein se ek mein jaata hai.

Do questions, order mein:

  1. "Kya yeh runtime par kabhi change hota hai?" — Nahi → yeh code ya constant hai → .text/.rodata mein jaata hai (sirf Flash, LMA = VMA).
  2. Agar haan, "Kya uski starting value zero hai?"
    • Non-zero start (int x = 5;) → .data. 5 yaad rakhna hai → Flash copy chahiye → do addresses (LMA ≠ VMA).
    • Zero start (int y; ya int z = 0;) → .bss. Uski starting value hamesha zero hoti hai, is liye store karne layak kuch nahi.

Step 5 — Sections ko do number lines par rakhna

KYA. Hum Step 1 ke Flash aur RAM strips par .text, phir .data, phir .bss place karte hain, ek moving pointer track karte hue jise location counter kaha jaata hai.

KYUN. Linker addresses guess nahi karta — woh sections ko ek ke baad ek stack karta hai, ek cursor advance karta hua. Us cursor ko move hote dekhna hi woh tarika hai jis se tum kisi bhi cheez ka final address predict kar sakte ho.

PICTURE. Flash top-down bharta hai: .text pehle (Flash ke ORIGIN par exactly start karte hue), phir .data ka load image usake bilkul baad. RAM alag se bharta hai: .data ka run copy RAM ke ORIGIN par, phir .bss usake bilkul baad. Notice karo .data dono strips par appear karta hai — yahi do-address idea concrete ho gaya.

Addresses seedha picture se padhna:

  • ::: Step 1 se ORIGINs
  • ::: location counter kitna aage gaya jab code place kiya — yahi wajah hai ki .data ki Flash copy Flash ke bilkul shuru mein nahi hai

Aur boundary symbols jo startup code ko chahiye honge (har ek bas "wahan location counter ki value" hai):

  • _sdata ::: RAM mein data ka start (run copy ka pehla byte)
  • _edata ::: RAM mein data ka end (aakhri byte ke baad wala byte)
  • _sidata ::: Flash mein init-data image ka start (load copy ka pehla byte)

Step 6 — Boot: copy loop (woh pal jab x 5 banta hai)

KYA. Hum woh startup code run karte hain jo .data ko Flash (LMA) se RAM (VMA) mein copy karta hai, byte by byte, jab tak RAM copy complete na ho jaaye.

KYUN. Reset ke bilkul baad, koi bhi C execute nahi hua aur RAM garbage hai (Step 3 ke red boxes). Agar hum yeh copy skip kar dete, to x padhne par jo bhi random bits RAM mein power-up ke waqt thi woh milti — 5 nahi. Yeh loop OS-loader ka kaam hai jo, bare-metal mein, tumhe karna hota hai.

PICTURE. Do pointers, p Flash mein _sidata se walk kar raha hai aur q RAM mein _sdata se, lockstep mein march karte hue. Har tick ek word Flash→RAM copy karta hai; red garbage boxes green ho jaate hain jab sahi value 5 aati hai.

  • p = &_sidata ::: source pointer Flash LMA par start karta hai (Step 5)
  • q = &_sdata ::: destination pointer RAM VMA par start karta hai
  • q < &_edata ::: tab tak chalte raho jab tak RAM cursor end mark tak na pahunche — yahan size = _edata − _sdata count ki tarah use hota hai
  • *q++ = *p++ ::: Flash se ek word padho, RAM mein likho, phir dono pointers aage badhao

Is loop ke baad, _sdata par RAM byte mein 5 hai. x finally initialize ho gaya.


Step 7 — Boot: zero loop (.bss blanking)

KYA. Ek doosra loop .bss RAM range mein walk karta hai aur har jagah 0 likhta hai.

KYUN. .bss ke paas koi Flash source nahi jis se copy kiya jaaye (Step 4) — kuch store nahi kiya gaya tha. Lekin C mein int y; guaranteed zero se start karta hai, aur RAM garbage mein power up hui hai. Is liye zeros hume khud create karne honge, yahan pe.

PICTURE. Ek pointer q _sbss se _ebss tak sweep karta hai, red garbage clean 0 boxes mein badalti hai jaise woh guzarta hai.

  • _sbss ::: RAM mein .bss region ka start (location counter, .data ke bilkul baad)
  • _ebss ::: .bss ka end; _ebss − _sbss region ki size hai, woh akela cheez jo Flash ne .bss ke baare mein store ki thi
  • *q++ = 0 ::: zero likho, aage badhao — koi source pointer nahi chahiye, kyunki source bas constant 0 hai

Sirf abhi stack pointer set hota hai aur main() call hota hai. Har global finally woh value hold karta hai jo C ne promise ki thi.


Step 8 — Degenerate & edge cases (reader ko kabhi wall se na takraao)

KYA. Hum dekhte hain kya hota hai boundaries par — empty aur overflowing cases — taaki koi scenario tumhe surprise na kare.

KYUN. Real firmware mein yeh hota hai. Agar tumne sirf "nice" case dekha hai, ek empty .bss ya ek too-big program ek bug ki tarah lagta hai jabki actually woh normal behaviour (ya ek diagnosable error) hai.

PICTURE. Degenerate situations ke char mini-panels.

Case Picture kya dikhati hai Actually kya hota hai
Empty .data (koi initialized globals nahi) _sdata == _edata Copy loop ki condition q < &_edata immediately false hai → zero iterations → sahi, koi crash nahi.
Empty .bss (koi zero globals nahi) _sbss == _ebss Zero loop 0 baar run karta hai. Theek hai.
Ek global int z = 0; .bss mein jaata hai, .data mein nahi Compilers dekhte hain value zero hai aur Flash bachane ke liye use .bss mein daalt hain — surprising lekin sahi.
RAM overflow (.data + .bss + stack ) RAM strip apne right edge se bahar nikal jaati hai Linker build time par error deta hai: region RAM overflowed. Mystery crash se behtar hai build error.

Ek-picture summary

Upar sab kuch, ek diagram mein compress kiya gaya: int x = 5; ki poori life — .data mein sort hua, Flash mein uski LMA par store hua, boot loop ne uske VMA in RAM par copy kiya, main() ke liye ready; aur int y; bina kisi Flash cost ke .bss mein blank hua.

non-zero, changes

zero start

stored at LMA

copy loop at boot

size only, no bytes

int x = 5

.data

int y

.bss

Flash image

RAM run copy VMA

zero loop at boot

main reads correct values

Recall Feynman: poori walkthrough ek story ki tarah sunao

Tum int x = 5; likhte ho. Compiler shoulders shrug karta hai — use value pata hai lekin kahan rehegi nahi. Linker script floor-plan ki tarah step in karta hai. Woh do rooms draw karta hai: ek attic (Flash) jo kabhi bhoolti nahi, house-number 0x08000000 se shuru hoti hai, aur ek desk (RAM) jo raat ko wipe ho jaati hai, 0x20000000 se shuru hoti hai.

Ab x ko ek problem hai: use yaad rakhna hai ki woh 5 hai (is liye value attic mein honi chahiye), lekin woh changeable bhi hona chahiye (is liye live copy desk par honi chahiye). Ek cheez, do ghar — attic mein ek load address aur desk par ek run address. Linker har variable ko is tarah sort karta hai: jo cheezein kabhi nahi badlti (code) attic mein rehti hain; jo cheezein badlti hain aur kisi value se start hoti hain woh .data mein jaati hain (do ghar); jo cheezein badlti hain aur zero se start hoti hain woh .bss mein jaati hain aur attic space bilkul waste nahi karti — linker bas likhta hai "itne khali boxes."

Jab tum power on karte ho, desk random junk se bhari hai. Ek chhota helper (startup code) attic mein jaata hai, x ka stored 5 uski desk spot par le aata hai (copy loop), phir .bss desk spots ko zero par saaf karta hai (zero loop). Tabhi main() call hota hai — aur har variable exactly woh hold karta hai jo tumhare C source ne promise kiya tha. Agar tumhara program kisi room ke liye zyada bada hai, linker build karne se mana kar deta hai mystery crash hone dene ki jagah. Bas yahi hai poora linker script, pictures mein.

Recall Quick self-check

5 physically kahan store hota hai, aur x chalte waqt kahan rehta hai? ::: 5 .data ki LMA Flash mein store hoti hai; x .data ki VMA RAM mein rehta aur badaltta hai; boot copy loop unhe bridge karta hai. int z = 0; .data ki jagah .bss mein kyun jaata hai? ::: Uski starting value zero hai, is liye Flash mein store karne layak kuch nahi — RAM mein boot par zero karna sasta padta hai. Copy/zero loops empty sections ko safely kyun handle karte hain? ::: Yeh while (q < end) ki tarah likhe jaate hain; jab start == end hota hai loop zero baar run karta hai.


Related vault topics: Startup code & Reset_Handler · Vector table & interrupt handling · Compilation pipeline — object files & relocation · Flash vs RAM tradeoffs · Stack vs Heap in embedded systems · ELF file format & sections · Volatile keyword & memory-mapped IO