Visual walkthrough — Calling conventions and ABI
5.1.10 · D2· Hardware › Instruction Set Architecture (ISA) › Calling conventions and ABI
Shuru karne se pehle, teen words jo har picture mein aate hain — yahan plain language mein define kiye gaye hain, taaki koi bhi symbol use hone se pehle tumne use dekha ho.
Neeche wali picture haari starting laboratory hai — iska layout yaad kar lo, kyunki baad ki har figure is same layout ko motion mein dikhati hai.

Step 1 — Problem: do anjaan log ek address pe milna chahte hain
KYA. Hamare paas ek caller hai (ise main kaho) aur ek callee (f). main us moment pe pahunchta hai jab woh chahta hai ki f chale, phir apni next instruction pe continue karna chahta hai.
YEH PROBLEM KYUN HAI. CPU sirf yahi karta hai: "rip jo instruction point kar raha hai use chalao, phir advance karo." Iske paas koi concept nahi "ja f karo, phir wapas aa." Wapas aane ka matlab hai: kisi ne return address yaad rakha hona chahiye. Sirf main ko woh address pata hai — isliye main ko jaane se pehle use record karna hoga.
PICTURE. Figure mein, main ke andar rip jaane wala hai. Amber question mark woh return address hai jo jump karte hi hamesha ke liye kho jaayega — jab tak hum ise save nahi karte.

Hamen us address ke liye ek fixed, agreed hiding place chahiye. Koi aisi jagah nahi jo main apni marzi se choose kare (f alag compile hoti hai aur main ka dimaag nahi padh sakti) — ek jagah jo convention se fixed ho. Sabse natural choice stack ki top hai.
Step 2 — call Invent Karna: return address push karo, phir jump karo
KYA. Hum ek combined action define karte hain:
Term by term:
- — us instruction ka address jo
callke theek baad hai. Yahi "yahan wapas aao" wala note hai. - — do micro-steps: (8 bytes neeche create karo, kyunki 64-bit machine pe address 8 bytes ka hota hai), phir ko us naye top slot mein likho.
- —
fka address set karo. CPU abfchalayega.
KYUN. Stack pe push karna "fixed hiding place" problem solve karta hai: f ko yeh jaanna zaroorat nahi ki caller kaun hai — sirf yeh jaanna hai ki return address stack ki top pe hai. Yeh ek rule duniya ke har caller ke liye kaam karta hai.
PICTURE. Dekho rsp 8 se neeche aata hai aur amber return address naye-khule slot mein land karta hai. rip f ki taraf swing karta hai.

Step 3 — Arguments kahan hain? Fixed naam se, Registers mein
KYA. main f ko kuch numbers (uske arguments) dena chahta hai. Hum ek baar aur hamesha ke liye decide karte hain ki woh kis order mein boxes mein jaate hain. System V AMD64 model use karte hue:
REGISTERS KYUN, AUR FIXED ORDER KYUN? Registers CPU ka sabse fast storage hai — rdi padhna kuch extra nahi lagta, memory padhna core se bahar trip lagti hai. Aur order agreement se fixed hona chahiye kyunki f main ko kabhi dekhe bina compile hoti hai; jedway f "argument #1 dhundh sakti hai" woh tabhi hai jab sab hamesha agree karein ki woh rdi mein hai.
SIRF 6 KYUN? Yeh ek empirical sweet spot hai: real functions ki vast majority 6 ya usse kam arguments leti hai, isliye woh calls kabhi arguments ke liye memory nahi chhutiyen — pure register speed.
PICTURE. Caller chhe named boxes left-to-right bharta hai; callee wahi boxes naam se padhegi.

Step 4 — Local scratch space banana: stack frame
KYA. f ko apni temporary memory chahiye ho sakti hai — locals, spilled values. Woh rsp ko neeche move karke unhe create karti hai:
SUBTRACT KYUN, STACK KYUN? rsp se subtract karna return address ke neeche bytes kholti hai — ek private room jo main ki memory se collide nahi kar sakta (woh sab upar waale addresses pe hai, untouched). Baad mein rsp ko wapas upar move karke yeh automatically free ho jaati hai. Is private room ko stack frame kehte hain (deep dive: Recursion and Activation Records).
PICTURE. Frame ek amber-outlined block ke roop mein neeche badhta hai; upar main ka frame grey aur safe hai.

Step 5 — Alignment invariant: kyun rsp ≡ 8 (mod 16) entry pe hota hai
KYA. rsp ki value ke baare mein ek numeric rule hai jis instant f shuru hoti hai:
padho as: "rsp ko 16 se divide karo, remainder 8 hai" — yaani rsp 16 ke multiple se 8 zyada hai.
YEH EXACT NUMBER KYUN? Convention kehti hai: call se bilkul pehle, rsp 16 ka clean multiple (16-byte aligned) hona chahiye. Phir call ne 8 bytes push kiye (return address, Step 2). 16 se aligned minus 8 = "16 ke multiple se 8 upar." Toh entry pe remainder exactly 8 hai — ek fingerprint jo prove karta hai alignment maintain ki gayi.
PARVAH KYUN KAREIN? Fast vector instructions jaise movaps demand karti hain ki jo memory woh chhuyen woh 16-byte aligned ho. Agar frame misaligned ho, woh slow nahi chaltiyen — woh segfault karti hain. Compiler frame size (Step 4) precisely pad karta hai taaki yeh invariant true rahe.
PICTURE. Stack ke saath ek ruler 16 ke multiples mark karta hai; return-address slot "+8" tick pe land karta hai, aur har well-formed frame woh offset maintain karta hai.

Step 6 — Answer return karna aur sab kuch undo karna
KYA. f khatam ho jaati hai. Teeen obligations, order mein:
Term by term:
- (a) result
raxmein jaata hai — woh fixed "answer box" jo caller padhega. (Floating resultsxmm0use karte hain; 128-bit resultsrdx:raxuse karte hain.) - (b)
rspko exactly se upar raise karta hai jo Step 4 mein subtract kiya tha — private room pile ko wapas de diya. Is ke baad,rspphir return address ki taraf point karta hai, bilkul entry pe jaisa tha. - (c) : top-of-stack (Step 2 ka return address) ko
ripmein padho, aurrspmein 8 add karo. CPU abmainki next instruction chala raha hai, aur stack byte-for-byte waisa hi hai jaisacallse pehle tha.
YEH EXACT UNDO KYUN? Ek call transparent honi chahiye: return ke baad, main apna stack aur apne saved registers unchanged dekhna chahiye, plus rax mein answer. (b) stack restore karta hai, (c) control flow restore karta hai, (a) payload deliver karta hai.
PICTURE. Steps 2–4 ka ulta backward chalaya gaya: frame upar collapse hoti hai, return address rip mein pop hota hai, rax answer ke saath glow karta hai.

Step 7 — Edge case A: 6 se zyada arguments (stack pe spill)
KYA. 7 arguments ke saath, args 1–6 registers fill karte hain; 7th stack pe spill ho jaata hai. Caller overflow args right-to-left push karta hai, taaki sabse left wala overflow argument sabse chhote address pe end up kare, aur call phir top pe return address push karta hai.
STACK PE KYUN, WOH LAYOUT KYUN? Sirf chhe argument registers hain — 7th ke paas aur koi jagah nahi. Right-to-left pushing overflow args ko ascending memory mein natural left-to-right order mein rakhta hai, taaki callee unhe predictably padh sake. Kyunki return address last push hota hai (Step 2), woh spilled args ke upar land karta hai, aur 7th argument theek uske baad hai:
Padho: "current top se 8 bytes upar" — 8-byte return address cross karo, aur arg 7 wahan hai.
PICTURE. 7th argument (amber) return address ke ek slot upar hai; chhe registers full hain.

Step 8 — Edge case B: "kaun kya save karta hai" ka split
KYA. f registers use karegi — shayad wahi jo main ki live values hold kar rahe hain. Do families:
- Caller-saved (volatile) —
rax, rcx, rdx, rsi, rdi, r8–r11.finhe freely overwrite kar sakti hai; agarmainko abhi bhi unki zaroorat hai,maininhe call se pehle save karta hai. - Callee-saved (non-volatile) —
rbx, rbp, r12–r15, rsp. Agarfinhe use karna chahti hai,fko entry pe purani value save karni hogi aurretse pehle restore karni hogi.
SPLIT KYUN, EK BLANKET RULE KYUN NAHI? Pure caller-saves rule un registers ko save karne mein waste karta hai jinhein f kabhi chhuye nahi. Pure callee-saves rule un registers ko save karne mein waste karta hai jin ki main ko ab zaroorat nahi. Registers ko do teams mein split karna har side ko sirf wahi save karne deta hai jo genuinely risk mein hai — minimum possible memory traffic.
PICTURE. Registers ki do coloured teams; f ek callee-saved box rbx ke use ko push rbx … pop rbx bracket mein wrap karti hai, ise unbroken wapas karti hai.

Ek-picture summary
Upar sab kuch, ek canvas pe: ek poore call mein stack ki zindagi. Time ke roop mein top-to-bottom padho. Registers args andar aur answer bahar le jaate hain; stack return address aur frame hold karta hai; alignment poore waqt +8 tick pe rehti hai.

Recall Feynman retelling — poora walkthrough plain words mein
Ek machine jo sirf "next instruction chalao" jaanti hai, code ka koi aur chunk borrow karke wapas aana chahti hai. Toh caller ek sticky-note likhta hai — "yahan wapas aao" — aur use neeche ki taraf badhne wale plates ki pile ki top plate pe slide karta hai (yahi hai call: return address push karo, phir jump karo). Sab agree karte hain, hamesha ke liye, ki kisi function ko diye gaye pehle kuch numbers chhe specific boxes mein rehte hain (rdi, rsi, rdx, rcx, r8, r9); agar chhe se zyada ho, toh leftovers sticky-note ke theek neeche plates pe stack ho jaate hain. Function apna private scratch work ke liye neeche plates create karta hai, hamesha pile ki height ko same "off-by-8" tick pe rakhta hai taaki fast vector instructions crash na karein. Kaam khatam hone pe, answer us box mein daalta hai jo sab padhte hain (rax), apni scratch plates wapas uthata hai, aur ghar jump karne ke liye top se sticky-note peel karta hai. Raaste mein, kuch boxes "tumhara trash karne ke liye" hain (caller-saved) aur kuch "borrow-and-return-unbroken" hain (callee-saved) — ek split jo is liye choose ki gayi taaki koi bhi aisa box kabhi save na kare jo genuinely risk mein nahi tha. Yahaan kuch bhi CPU mein built nahi tha: yeh sab agreement hai, aur woh agreement hi linkable ABI ke dil mein calling convention hai.
Flashcards
Return address ko stack pe save kyun kiya jaana chahiye na ki caller ke chosen kisi fixed register mein?
call f kaun se do micro-steps perform karta hai?
Function mein entry ke baad, [rsp] mein kya hota hai?
call ne push kiya tha.Function entry pe rsp ≡ 8 (mod 16) kyun hota hai?
call se pehle rsp 16-byte aligned tha, aur call ne 8 bytes (return address) push kiye, remainder 8 chhood ke.