5.1.10 · D5 · HinglishInstruction Set Architecture (ISA)

Question bankCalling conventions and ABI

2,180 words10 min read↑ Read in English

5.1.10 · D5 · Hardware › Instruction Set Architecture (ISA) › Calling conventions and ABI

Questions se pehle do visual anchors — pehle inhe study karo, phir Q&A inhe refer karta hai.

Figure — Calling conventions and ABI

Upar ka stack frame high address se neeche ki taraf dikhata hai: incoming stack arguments (7th+), return address jo call ne push kiya, saved callee-saved registers, local variables, aur rsp ke neeche red zone. Neeche saare stack-related questions is picture ke kisi slot ko point karte hain.

Figure — Calling conventions and ABI

Upar ki register table "who saves what" split hai — caller-saved (volatile) orange mein, callee-saved (non-volatile) violet mein — floating-point xmm registers ke saath bhi, jinke baare mein questions poochhe jaate hain.

Figure — Calling conventions and ABI

Upar ka quadrant SysV AMD64 (Linux/macOS) aur Microsoft x64 (Windows) ko usi CPU par compare karta hai — same hardware, jaan-boojhkar alag rules.


True or false — justify karo

Har argument hamesha ek register mein pass hota hai.
False. Sirf pehle kuch (SysV AMD64 mein 6 integer/pointer args — figure s02 dekho) registers mein jaate hain; baaki figure s01 ke upar ke slots mein stack par spill ho jaate hain. Dekho Stack and Stack Frames.
CPU hardware jaanta hai ki "function argument" kya hota hai.
False. CPU ke paas sirf registers aur memory hoti hai; "argument" ek pure software convention hai jo pehle se agree ki gayi hoti hai — hardware yeh concept kabhi nahi dekhta.
Do .o files jo ek calling convention share karti hain, unka link aur run correctly saath mein guaranteed hai.
False. Unhe ABI ke baaki hisson par bhi agree karna hoga — type sizes, struct layout, alignment, name mangling. Shared calling convention zaroori hai lekin kaafi nahi. Dekho Linkers and Object File Format.
Agar koi function kabhi rbx use nahi karta, phir bhi use use push aur pop karna hoga.
False. Callee-saved discipline kehti hai "ise tabhi save karo jab use karo." Jo function rbx ko kabhi nahi chhoota, woh use akela chhod deta hai — koi save zaroori nahi.
Caller-saved registers callee-saved ones se zyada safe hote hain.
False — woh "safer" nahi hain, sirf alag rule se govern hote hain. Caller-saved value ek call ke baad tabhi survive karta hai jab caller khud use pehle save kare; callee use freely clobber kar sakta hai (figure s02 mein orange rows).
call instruction ek primitive hai jo hardware specifically functions ke liye provide karta hai.
Partly true lekin misleading. call sirf push return_address; jmp target hai — do primitives ka ek convenient combination. Function abstraction phir bhi convention hai, hardware nahi.
Return address ek register mein rehta hai.
SysV AMD64 mein False — call use stack par push karta hai (figure s01 mein labelled slot). Kuch ISAs jaise ARM64 (AAPCS) use link register x30 mein rakhte hain — dekho x86-64 vs ARM64 AAPCS.
Floating-point arguments integer arguments ke saath same registers share karte hain.
False. Integers rdi/rsi/rdx/rcx/r8/r9 use karte hain; floats ek alag pool xmm0–xmm7 use karte hain. Inhe independently count kiya jaata hai.
SysV AMD64 mein xmm floating-point registers sab callee-saved hote hain.
False. SysV mein xmm0–xmm15 sab caller-saved (volatile) hain — callee unhe kisi bhi waqt clobber kar sakta hai, isliye caller ko ek call ke across kisi live float ko save karna hoga. (Contrast: Microsoft x64 mein xmm6–xmm15 callee-saved hain — figure s03 dekho.)
ABI ek source-code concept hai jaise API.
False. API source-level hai (names aur signatures); ABI binary-level contract hai jo compilation ke baad survive karta hai.

Error dhundho

"Apne function ke andar rbx use karne ke liye, main entry par rbp push karta hoon aur ret se pehle pop karta hoon."
Galat register save kiya. Agar tum rbx clobber karte ho toh tumhe rbx khud save karna hoga — ABI ka promise per register hai: caller har named callee-saved register par individually trust karta hai. rbp save karna caller ka rbx corrupt chhod deta hai.
"7 arguments? Main 7th ko r10 mein rakhunga kyunki yeh r9 ke baad ka next register hai."
Galat. ABI argument sequence exactly rdi/rsi/rdx/rcx/r8/r9 par fix karta hai taaki callee — bina caller ki knowledge ke compile hua — jaanta ho exactly kahan dekhna hai. r10 caller-saved scratch ke roop mein define hai, argument slot ke roop mein nahi, isliye callee use kabhi nahi read karega. 7th arg stack par jaata hai.
"Callee 7th stack argument ko [rsp] se read karta hai."
Galat offset. call ne pehle return address push kiya, isliye entry par rsp usi ko point kar raha hai, argument ko nahi. ABI 7th argument ko return address ke bilkul upar rakhta hai, jo ==[rsp+8]== deta hai (figure s01 mein do adjacent slots dekho).
"Maine ek local ke liye rsp se 8 subtract kiya, toh alignment theek hai."
Shayad broken hai. Algebra: call ke bahar rsp ≡ 0 (mod 16); call 8 bytes push karta hai isliye entry par rsp ≡ 8 (mod 16); 8 subtract karne par 0 (mod 16) milta hai, lekin agla call jo tum karoge woh aur 8 push karega aur re-misalign kar dega. Frame ko is size ka rakhna hoga ki rsp ≡ 0 (mod 16) ho har call se bilkul pehle — neeche WHY question dekho.
"Mera function do values return karta hai, toh main ek rax mein aur ek rbx mein return karta hoon."
Galat register. ABI ek 128-bit result ko pair rdx:rax ke roop mein define karta hai precisely isliye kyunki dono caller-saved scratch hain — callee ke liye unhe overwrite karna free hai. rbx callee-saved hai, yani caller ki state ko call ke across rakhne ke liye reserved hai, isliye uske through return karna ek value clobber kar deta jo caller trust karta hai.
"Caller arguments call execute karne ke baad set up karta hai."
Galat order. Arguments call se pehle jagah par hone chahiye, kyunki call turant callee ko control transfer kar deta hai — baad mein callee already rdi/rsi/… read kar raha hota hai.

Why questions

Registers ko caller-saved aur callee-saved mein kyun split karte hain ek rule ki jagah?
Ek pure caller-saves rule un registers par saves waste karta hai jinhe callee kabhi touch nahi karta; ek pure callee-saves rule un registers par saves waste karta hai jinhe caller baad mein zaroorat nahi hoti. Split karna (figure s02) har side ko sirf wahi save karne deta hai jo actually risk mein hai.
SysV AMD64 exactly pehle 6 args registers mein kyun pass karta hai?
Yeh ek empirical sweet spot hai — zyaadatar functions ke ≤ 6 arguments hote hain, isliye zyaadatar calls kabhi args ke liye memory touch nahi karti, jo ek badi speed win deta hai. Dekho Registers and Register File.
call se pehle rsp 16-byte aligned kyun hona chahiye?
Step by step: (1) SSE instructions jaise movaps fault karte hain jab tak unka memory operand 16-byte aligned na ho. (2) Compiler aligned locals ko rsp ke relative rakhta hai. (3) Kyunki call ek 8-byte return address push karta hai, ABI rsp ≡ 0 (mod 16) call se pehle require karta hai taaki callee ke andar rsp ≡ 8 (mod 16) ho, aur callee phir ek padded frame subtract karke 16 ke multiple par wapas aa sake. Boundary par ek baar yeh guarantee karna har aligned local ko free bana deta hai.
Stack arguments right-to-left kyun push hote hain?
Taaki sabse left wala overflow argument sabse neeche address par khatam ho, callee ko unhe ek predictable, ascending order mein read karne ke liye (figure s01 ke top slots).
Recursion ko registers ki jagah stack kyun chahiye?
Har nested call ko locals aur return address ki apni copy chahiye; registers ek fixed finite set hain aur overwrite ho jaate, isliye har activation ko ek fresh stack frame milta hai. Dekho Recursion and Activation Records.
Ek system call ordinary function call ke saath same register order kyun nahi use kar sakta?
Kernel apna khud ka convention define karta hai (jaise rax mein syscall number, rdi… mein args, aur r10 rcx ki jagah leta hai kyunki syscall instruction rcx ko clobber karta hai). Dekho System Calls and Syscall Interface.
C++ ko C ABI ke upar name mangling kyun chahiye?
Overloading aur namespaces ka matlab hai kai functions ek source name share karte hain; linker ko distinct binary symbols chahiye, isliye compiler types ko name mein encode karta hai. Dekho Name Mangling in C++.
Windows alag x86-64 convention kyun use karta hai Linux se?
Dono operating systems ne independently standardize kiya; hardware koi convention impose nahi karta, isliye har OS ne apna choose kiya (Windows par 4 arg registers vs SysV par 6, alag volatile sets — figure s03). Yahi wajah hai koi Linux .so Windows .dll ke against link nahi hoga.

Edge cases

Ek function jiske zero arguments hain — kya convention phir bhi apply hoti hai?
Haan. Woh simply koi argument registers use nahi karta, lekin phir bhi callee-saved discipline, stack alignment, aur agar result hai toh rax mein return karna owed hai.
Ek function jo kabhi return nahi karta (jaise exit call karta hai) — kya use phir bhi callee-saved registers preserve karne chahiye?
Koi practical obligation nahi, kyunki control kabhi caller ke paas wapas nahi aata. Preservation ka promise tabhi matter karta hai jab caller resume kare.
Ek leaf function (kuch call nahi karta) thodi locals ke saath — kya use stack frame chahiye?
Aksar nahi. SysV har function ko ek red zone deta hai: rsp ke neeche 128 bytes (figure s01 ke bottom mein shaded region) jo ek leaf function rsp ko move kiye bina scratch ke roop mein use kar sakta hai. Yeh sirf leaves ke liye kaam karta hai kyunki koi bhi call callee ko woh region overwrite karne dega. Yeh sub rsp / add rsp pair ko poori tarah bachata hai.
Ek struct jo 16 bytes se bada hai value se pass karna — woh kahan jaata hai?
ABI use MEMORY classify karta hai, isliye caller use stack argument area (figure s01 ke top) mein copy karta hai, registers mein nahi, kyunki yeh two-register class limit se zyada hai. Agar ek return value itni badi ho, toh caller rdi mein ek hidden pointer pass karta hai (jise sret, "structure return" kehte hain) jo usne allocate ki space ko point karta hai, aur callee result wahan likhta hai — kyunki koi bhi register ise wapas carry karne ke liye itna wide nahi hai.
10000 depth par ek recursive call — convention ki kaun si property ise bilkul kaam karati hai?
Har call rsp se neeche ki taraf ek fresh frame kaarti hai, isliye activations kabhi collide nahi hote — jab tak stack khatam na ho (stack overflow), woh boundary case jahan invariant ek hard memory limit se milta hai.

Recall One-line self-test

Sab cover karo: kya tum bata sakte ho kaun kaun sa register save karta hai aur split kyun exist karti hai? ::: Caller volatile registers save karta hai jis par use abhi bhi zaroorat hai; callee koi bhi non-volatile register save karta hai jo woh use karta hai — split total memory traffic minimize karti hai har side ko sirf wahi save karaake jo actually risk mein hai.