An ABI (Application Binary Interface) is a convention between binary components, covering data layout, calling conventions, symbol and object formats, and more. Even if the code on either side of a function boundary is generated by different compilers, they must agree on where arguments are located, which registers may be modified, and how return values are represented.
Violating an ABI can cause an immediate crash, or it may silently read incorrect arguments or corrupt a value that is used later. This article uses common user-mode x86-64 calling conventions as examples; system calls, kernel code, and special calling conventions require separate treatment.
Classify Arguments First, Then Assign Locations
For the first six common integer or pointer arguments in System V AMD64, the registers RDI, RSI, RDX, RCX, R8, and R9 are used; floating-point arguments follow a separate set of XMM register rules. Aggregate types must be classified according to the ABI; you cannot simply stuff all arguments into the same "first six" list.
For Windows x64, the first four argument locations use RCX, RDX, R8, R9, or the corresponding XMM0–3 depending on their types. The caller reserves at least 32 bytes of register parameter home/shadow space. Mixed integer and floating-point arguments do not form two independent, unlimited queues of the "top four." Microsoft x64 Calling Convention
Item
System V AMD64 Common Rules
Windows x64 Common Rules
Integer/Pointer Registers
RDI, RSI, RDX, RCX, R8, R9
First four positions use RCX, RDX, R8, R9
Scalar Floating-Point
Allocated according to rules XMM0–7
First four positions correspond to XMM0–3
Shadow Space
No mandatory four-slot area like Windows
Caller reserves 32 bytes
Red Zone
User-mode has ~128 bytes reserved
No equivalent guarantee
Aggregates, Variadic, Vectors
Check classification and special rules
Check independent rules
Return values are also classified by type: scalar integers typically use RAX, scalar floating-point typically uses XMM0, some aggregates can be split across multiple registers, and others are returned via a hidden result pointer. The statement "128-bit structures are uniformly placed in RDX:RAX" is incorrect. AMD64 ABI
Why Register Allocation Differs for the Same Mixed Argument Declaration
Consider the fixed prototype double mix(int a, double b, int c, double d), which does not involve variadic arguments or aggregates. System V consumes integer and floating-point argument sequences separately: a uses EDI, b uses XMM0, c uses ESI, and d uses XMM1. Windows x64 selects registers based on argument position: a uses ECX, b uses XMM1, c uses R8D, and d uses XMM3.
Argument
System V AMD64
Windows x64
a: 1st argument, int
EDI
ECX
b: 2nd argument, double
XMM0
XMM1
c: 3rd argument, int
ESI
R8D
d: 4th argument, double
XMM1
XMM3
In the table, int only uses the corresponding 32-bit value; do not infer from the declaration that the remaining bits of the register can be used to pass other arguments. The following source file does not depend on platform headers and can generate assembly for both targets separately:
/* mix.c */doublemix(inta,doubleb,intc,doubled){return a + b + c + d;}
Instructions converting integers to double can identify the two integer sources, followed by observing the floating-point inputs along the addition chain. Here we only generate assembly across targets; there is no need to run the Windows program. The return value is XMM0 in both cases, but the input layout differs, and these differences cannot be eliminated by casting function pointers. Microsoft Parameter Passing
Why are positional slots not independent type queues?
Changing argument types recomputes locations. System V advances separate int/double sequences; Windows keeps positional slots, so a double in position2 uses XMM1 even when XMM0 was unused. Beyond position4 this example uses stack slots regardless of unused registers.
Preparing the visual
Why are positional slots not independent type queues?
In this example System V uses separate integer/FP queues; Windows selects GPR/XMM by the first four argument positions, so argument5 cannot restart at XMM0.
{"id":"abi-argument-positions","title":"Why are positional slots not independent type queues?","summary":"In this example System V uses separate integer/FP queues; Windows selects GPR/XMM by the first four argument positions, so argument5 cannot restart at XMM0.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div id=\"arguments\" class=\"choices\"></div><div id=\"locations\" class=\"table\"></div><div class=\"metrics\"><div><span data-i18n=\"space\"></span><strong id=\"space\"></strong></div></div><p class=\"hint\" data-i18n=\"hint\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n#arguments{grid-template-columns:repeat(3,minmax(0,1fr))}#locations .tr{grid-template-columns:.6fr 1fr 1fr}#locations .tr>div{min-height:4.8em}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}let types=['int','double','int','double','double','int'];function draw(){let ni=0,nf=0;const sys=['EDI','ESI','EDX','ECX','R8D','R9D'],win=['ECX','EDX','R8D','R9D'],rows=types.map((type,i)=>['p'+(i+1)+': '+type,type==='int'?sys[ni++]:'XMM'+nf++,i<4?(type==='int'?win[i]:'XMM'+i):'[RSP+'+(40+(i-4)*8)+']']);types.forEach((type,i)=>{let b=document.querySelector('[data-arg=\"'+i+'\"]');if(!b){b=document.createElement('button');$('#arguments').append(b);}b.textContent='p'+(i+1)+': '+type;b.dataset.arg=i;b.setAttribute('aria-pressed',String(type==='double'));b.onclick=()=>{types[i]=type==='int'?'double':'int';draw()};});table('locations',[['','System V','Windows'],...rows]);set('space','32 byte');$('#locations').dataset.rows=JSON.stringify(rows);}draw();","audio":false,"strings":{"heading":"Why are positional slots not independent type queues?","hint":"Each argument button toggles type; changing types compares a new signature.","intro":"Toggle six arguments between int/double. Both ABIs show locations for a fixed prototype, exposing mixed-type allocation.","reset":"Reset","scope":"Fixed prototype with six scalar int/double args, no aggregates, variadics, vectors or hidden args. Stack offsets are callee-entry RSP; Windows also reserves32-byte home space.","scopeLabel":"Model scope and assumptions","space":"Windows required home space"}}
Saving Conventions: Who Ensures Values Survive Across Calls
"Caller-saved" means the callee may modify the register; if the caller still needs the old value, it must save it or move it to a different location first. "Callee-saved" means that if the callee uses that register, it must restore the caller's value before returning.
In System V, RBX, RBP, and R12–R15 are common callee-saved registers, and RSP must be restored according to the calling convention upon return. RAX, RCX, RDX, RSI, RDI, and R8–R11 may be destroyed by the call. Vector registers and status registers also have their own rules; do not check only general-purpose registers.
This directly affects register allocation: values that need to survive across calls cannot be placed unprotected in locations that may be destroyed by the call.
Stack Layout and Alignment
For common System V calls, RSP satisfies 16-byte alignment before the call. After the call pushes the 8-byte return address, (RSP+8) at the function entry satisfies this alignment. Some cases involving vectors passed on the stack have stricter requirements; refer to the corresponding ABI rules.
Therefore, when demonstrating seven integer arguments, you cannot simply write push 7th_arg; call while completely ignoring the current stack state and padding. The caller may reserve a block of argument space and then write into it; there is no need to push arguments one by one in source code order.
Local variables are not necessarily on the stack; after optimization, they may be in registers, replaced by constants, or disappear entirely. The frame pointer may also be omitted; unwind information describes how to restore the caller's state, not just a table for finding the old RBP from RSP. At runtime in ELF, unwinding often involves .eh_frame and other information.
Prologue and Epilogue: Code that Satisfies Conventions is Not a Fixed Template
The prologue may save callee-saved registers, allocate stack space, and set up the frame pointer; the epilogue restores the corresponding state. Leaf functions may not perform these actions, and optimization can delay saving until it is actually needed.
Below is a GNU assembly example calling an external twice(long) under Linux System V and adding 1. Using Intel syntax, the entry RSP modulo 16 is 8; subtracting 8 establishes alignment for the subsequent call.
The first long argument is already in RDI, and the return value is in RAX; this function does not use registers like RBX that require extra saving. CFI describes the CFA (CFA is the Canonical Frame Address) along with stack adjustments, allowing the unwinder to restore the caller's state.
You Must Preserve Original Arguments if You Need Them After the Call
Change the calculation to twice(x) + x. x is initially in RDI, and twice is allowed to overwrite RDI, so adding RDI directly after return is incorrect. Below, we first save the caller's RBX to the stack, then use RBX to preserve x; twice must restore the RBX it received, and finally this function restores the upper caller's old value.
# keep_x.s: GNU Assembly, Linux System V AMD64
.intel_syntax noprefix
.text
.globl keep_x
.type keep_x, @function
keep_x:
.cfi_startproc
push rbx
.cfi_def_cfa_offset 16
.cfi_offset rbx, -16
mov rbx, rdi
call twice@PLT
add rax, rbx
pop rbx
.cfi_def_cfa_offset 8
.cfi_restore rbx
ret
.cfi_endproc
.size keep_x, .-keep_x
.section .note.GNU-stack,"",@progbits
Entry RSP modulo 16 is 8; the pushed 8 bytes both save RBX and make RSP modulo 16 equal to 0 before the call. You should not copy the sub rsp, 8 from the previous section and subtract again, or you will break the alignment at this call site.
/* abi-main.c: Compile together with keep_x.s */externlongkeep_x(long);longtwice(longx){return x *2;}intmain(void){returnkeep_x(7)!=21||keep_x(-3)!=-9;}
After executing cc -O2 abi-main.c keep_x.s -o abi-demo and running abi-demo, the normal exit status is 0. Using only these limited small values here avoids letting signed overflow in long multiplication or addition mask ABI issues.
A compiler happening not to modify RDI does not prove that the incorrect writing is correct. Checking call boundaries should be based on what state the callee is allowed to destroy, rather than just observing a single instance of machine code; implementation changes, instrumentation, or linking to another compatible definition may expose latent errors.
Where can x survive a call reliably?
Preserving x, restoring the caller’s register and aligning the call are independent checks. Construct a numeric21 that corrupts RBX, or correct values with misalignment from an extra stack subtraction. Numbers are symbolic evaluation of the example callee; after an ABI violation they are not guarantees of real machine behavior.
Preparing the visual
Where can x survive a call reliably?
The callee may clobber RDI. Preserving x in RBX requires saving the caller’s old RBX; that push already aligns the stack, so another sub rsp,8 breaks alignment.
{"id":"abi-preservation-alignment","title":"Where can x survive a call reliably?","summary":"The callee may clobber RDI. Preserving x in RBX requires saving the caller’s old RBX; that push already aligns the stack, so another sub rsp,8 breaks alignment.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"mode\"><button data-mode=\"none\" data-i18n=\"none\"></button><button data-mode=\"bare\" data-i18n=\"bare\"></button><button data-mode=\"saved\" data-i18n=\"saved\"></button></div><label class=\"check\"><input type=\"checkbox\" id=\"extra\"><span data-i18n=\"extra\"></span></label><div id=\"states\" class=\"table\"></div><div class=\"metrics\"><div><span data-i18n=\"result\"></span><strong id=\"result\"></strong></div><div><span data-i18n=\"rbx\"></span><strong id=\"rbx\"></strong></div><div><span data-i18n=\"align\"></span><strong id=\"align\"></strong></div></div><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"ok\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"bad\"></p></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.metrics{grid-template-columns:repeat(3,minmax(0,1fr))}.metrics strong{font-size:20px}#states .tr{grid-template-columns:1fr 1fr}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}let mode='saved';function draw(){const push=mode==='saved'?8:0,extra=$('#extra').checked?8:0,mod=(8-push-extra+32)%16,result=mode==='none'?113:21,rbx=mode==='bare'?7:90;table('states',[['entry','RDI=7; RBX=90'],['before call','RSP−'+(push+extra)],['callee','RAX=14; RDI=99'],['after restore','RBX='+rbx]]);set('result',result);set('rbx',rbx);set('align',mod);const valid=result===21&&rbx===90&&mod===0;set('explanation',t(valid?'ok':'bad'));$('#states').dataset.valid=String(valid);pressed(mode);}$('#extra').onchange=draw;document.querySelectorAll('[data-mode]').forEach(b=>b.onclick=()=>{mode=b.dataset.mode;draw()});draw();","audio":false,"strings":{"align":"RSP mod16 before call","bad":"A call contract fails; a correct numeric result cannot excuse other violations.","bare":"Use RBX, no save","extra":"Extra sub/add rsp,8","heading":"Where can x survive a call reliably?","intro":"Goal: twice(x)+x with x=7. Choose preservation and optional extra8-byte stack adjustment; inspect values and alignment.","mode":"Preservation plan","none":"Rely on RDI","ok":"Value preservation, RBX restoration and alignment all hold.","rbx":"Returned RBX (must be90)","reset":"Reset","result":"Result (target21)","saved":"Save/restore RBX","scope":"Fixed ordinary System V AMD64 scalar call: entry RSP mod16=8, caller RBX90. twice returns14 and legally clobbers RDI to99; checks this boundary only.","scopeLabel":"Model scope and assumptions"}}
Red Zone: Temporary Values Cannot Cross Calls Unprotected
System V user-mode provides a 128-byte red zone below RSP, which must adhere to relevant conventions for signal handling, etc. Functions can use it to save temporary data without adjusting RSP; this is particularly common in leaf functions.
However, nested calls will use stack space at lower addresses, so you cannot expect values in the red zone to safely cross ordinary function calls. Non-leaf functions can also use temporary data that does not need to survive across calls in appropriate intervals, so the statement "only leaf functions can use it in any sense" is too absolute. Kernels, interrupts, and other platforms cannot directly copy this guarantee.
Variadic Arguments: The Caller Knows the Actual Arguments, the Callee Retrieves Them According to Convention
Declarations for functions like printf do not list all actual argument types, but the compiler at the call site knows the actual expressions and applies default argument promotions, such as promoting float to double. Whether the format string matches the actual arguments is still a matter of language and interface checking.
System V uses AL for variadic calls to indicate the upper bound of the number of vector register arguments used, with the value range defined by the ABI. The callee establishes register save areas as needed, and va_list tracks the register area and stack argument area. It is not the case that the caller universally pre-writes all XMM arguments into the callee's va_list.
Windows' variadic rules are different; floating-point actual arguments may need to be placed in general-purpose registers at relevant positions. Hand-written bridges across ABIs must handle this specifically and cannot simply replace argument register names.
PIC and PIE: Reducing Absolute Address Dependencies
Position-independent code often uses PC-relative addressing to access local data and code, and uses GOT, PLT, or other convention paths for symbols that can be dynamically bound. Not all PIC symbol accesses necessarily incur an extra GOT indirection: binding, visibility, and linker relaxation may allow direct relative access.
PIE (Position Independent Executable) is one form of position-independent executable, used in conjunction with load address randomization. Whether a certain relocation is needed and where it occurs should be combined with object format and symbol rules. See Linking and Loading.
Cross-Language Boundary Quick Reference
Check function prototypes, data size and alignment, aggregate classification, calling conventions, whether exceptions can cross boundaries, who frees memory, and symbol names. Declarations like extern "C" can specify some linking and calling rules, but they do not automatically make all language objects have compatible layouts and lifetimes.