Calling Convention
Calling Convention
Abhijit A M
The need for calling convention
Compiler needs to map the features of C into processor’s features, and then generate machine
code
In reality, the language designers design a language feature only after answering the question of
conversion into machine code
The need for calling convention
LIFO
Last in First Out
Must need a “stack” like feature to implement them
Processor Stack
Processors provide a stack pointer
%esp on x86
Instructions like push and pop are provided by hardware
They automatically increment/decrement the stack pointer. On x86 stack grows downwards (substract from esp!)
Unlike a “stack data type” data structure, this “stack” is simply implemented with only the esp (as the “top”). The
entire memory can be treated as the “array”.
Function calls
endbr64
Normally a NOP
Let’s see some examples now
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main:
X ebp
rbp
endbr64
pushq %rbp
Y movq %rsp, %rbp
X
subq $16, %rsp
movl $20, -8(%rbp)
rsp movl $30, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, %edi
call f
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
leave
ret
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main:
X ebp
rbp
endbr64
pushq %rbp
Y movq %rsp, %rbp
X
subq $16, %rsp
movl $20, -8(%rbp)
rsp movl $30, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, %edi
call f
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
leave
ret
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main:
X ebp
rbp
endbr64
pushq %rbp
Y movq %rsp, %rbp
X
subq $16, %rsp
movl $20, -8(%rbp)
rsp movl $30, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, %edi
call f
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
leave
ret
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main:
X ebp
rbp
endbr64
pushq %rbp
Y movq %rsp, %rbp
X
subq $16, %rsp
b 30 movl $20, -8(%rbp)
a 20 rsp movl $30, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, %edi
call f
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
leave
ret
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main:
X ebp
rbp
endbr64
pushq %rbp
Y movq %rsp, %rbp
X
subq $16, %rsp
b 30 movl $20, -8(%rbp)
a 20 rsp movl $30, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, %edi
call f
movl %eax, -4(%rbp)
edi = 20 movl -4(%rbp), %eax
leave
ret
int main() {
int a = 20, b = 30;
b = f(a);
return b;
}
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
Leave edi = 20
ret
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
Leave edi = 20
ret
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
Leave edi = 20
ret
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
x 20 Leave edi = 20
ret
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
x 20 Leave edi = 20
ret
int main() { eax = 20
int f(int x) {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
x 20 Leave edi = 20
ret
int main() { eax = 23
int f(int x) {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
y 23 RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
x 20 Leave edi = 20
ret
int main() { eax = 23
int f(int x) {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
y 23 RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax edi = 20
x 20 Leave
ret Eax = 23
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b;
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 30 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
y 23 RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax edi = 20
x 20 Leave
ret eax = 23
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b; eip = RA
} }
main: f:
X ebp
rbp
endbr64 endbr64
pushq %rbp pushq %rbp
Y movq %rsp, %rbp movq %rsp, %rbp
X
subq $16, %rsp movl %edi, -20(%rbp)
b 23 movl $20, -8(%rbp) movl -20(%rbp), %eax
a 20 rsp movl $30, -4(%rbp) addl $3, %eax
movl -8(%rbp), %eax movl %eax, -4(%rbp)
RA movl %eax, %edi movl -4(%rbp), %eax
Y-4 call f popq %rbp
y 23 RA: ret
movl %eax, -4(%rbp)
movl -4(%rbp), %eax edi = 20
x 20 leave
ret eax = 23
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b; eip = RA
} }
main:
endbr64 f:
X ebp
rbp
pushq %rbp endbr64
movq %rsp, %rbp pushq %rbp
Y subq $16, %rsp movq %rsp, %rbp
X
movl $20, -8(%rbp) movl %edi, -20(%rbp)
b 23 movl $30, -4(%rbp) movl -20(%rbp), %eax
a 20 rsp movl -8(%rbp), %eax addl $3, %eax
movl %eax, %edi movl %eax, -4(%rbp)
RA call f movl -4(%rbp), %eax
Y-4 RA: popq %rbp
y 23 movl %eax, -4(%rbp) ret
movl -4(%rbp), %eax
leave edi = 20
x 20 # mov rbp rsp; pop rbp
ret eax = 23
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b; eip = RA
} }
main:
endbr64 f:
X ebp
rbp
pushq %rbp endbr64
movq %rsp, %rbp pushq %rbp
Y subq $16, %rsp movq %rsp, %rbp
X
movl $20, -8(%rbp) movl %edi, -20(%rbp)
b 23 movl $30, -4(%rbp) movl -20(%rbp), %eax
a 20 rsp movl -8(%rbp), %eax addl $3, %eax
movl %eax, %edi movl %eax, -4(%rbp)
RA call f movl -4(%rbp), %eax
Y-4 RA: popq %rbp
y 23 movl %eax, -4(%rbp) ret
movl -4(%rbp), %eax
leave edi = 20
x 20 # mov ebp esp; pop ebp
ret eax = 23
int f(int x) { int main() {
int y; int a = 20, b = 30;
y = x + 3; b = f(a);
return y; return b; eip = RA
} }
Further on calling convention
Local variables
Are visible only within the function
Recursion: different copies of variables
Stored on “stack”
Registers
Are only one copy
Are within the CPU
Local Variables & Registers conflict
Compiler’s dillemma: While generating code for a function, which registers to use?
The register might have been in use in earlier function call
Caller save and Callee save registers
Higher Addresses
F() called g()
[ebp+16] Parameters-i refers to
parameter 3
parameter 2
[ebp+12] parameters passed by f() to g()
[ebp+8]
parameter 1
Local variable is a variable in
g()
(return address)
ebp
(saved value of ebp)
[ebp-4]
local variable 1
Return address is the location
saved value of edi
https://www.cs.virginia.edu/~evans/cs216/guides/x86.html
32 bit vs 64 bit calling convention