5.1.10 · D2 · HinglishInstruction Set Architecture (ISA)

Visual walkthroughCalling conventions and ABI

2,626 words12 min read↑ Read in English

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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI

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 call ke 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.
  • f ka address set karo. CPU ab f chalayega.

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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI

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 rax mein jaata hai — woh fixed "answer box" jo caller padhega. (Floating results xmm0 use karte hain; 128-bit results rdx:rax use karte hain.)
  • (b) rsp ko exactly se upar raise karta hai jo Step 4 mein subtract kiya tha — private room pile ko wapas de diya. Is ke baad, rsp phir return address ki taraf point karta hai, bilkul entry pe jaisa tha.
  • (c) : top-of-stack (Step 2 ka return address) ko rip mein padho, aur rsp mein 8 add karo. CPU ab main ki next instruction chala raha hai, aur stack byte-for-byte waisa hi hai jaisa call se 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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI

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. f inhe freely overwrite kar sakti hai; agar main ko abhi bhi unki zaroorat hai, main inhe call se pehle save karta hai.
  • Callee-saved (non-volatile)rbx, rbp, r12–r15, rsp. Agar f inhe use karna chahti hai, f ko entry pe purani value save karni hogi aur ret se 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.

Figure — Calling conventions and ABI

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.

Figure — Calling conventions and ABI
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?
Kyunki callee alag compile hoti hai aur caller ko jaanti nahi; ek fixed stack location (call ke baad stack ki top) uniformly har possible caller ke liye kaam karta hai.
call f kaun se do micro-steps perform karta hai?
push rip_next (rsp ← rsp − 8, return address store karo), phir jmp f (rip ← f ka address).
Function mein entry ke baad, [rsp] mein kya hota hai?
Woh return address jo call ne push kiya tha.
Function entry pe rsp ≡ 8 (mod 16) kyun hota hai?
Kyunki call se pehle rsp 16-byte aligned tha, aur call ne 8 bytes (return address) push kiye, remainder 8 chhood ke.
7th integer argument kahan rehta hai, aur ise kaise padha jaata hai?
Stack pe, return address ke theek upar, entry pe [rsp+8] pe.
Registers ko caller-saved aur callee-saved mein kyun split kiya jaata hai ek rule ki jagah?
Total saves minimize karne ke liye — har side sirf wahi registers save karta hai jo actually risk mein hain (callee kabhi na chhua vs caller ko ab zaroorat nahi).