Assembly Language: Function Calls: Goals of This Lecture
Assembly Language: Function Calls: Goals of This Lecture
Function Calls
1
Problem 1: Calling and Returning
Q: # Function Q
…
jmp R # Call R
Rtn_point2:
…
6
2
Attempted Solution: Use Register
• Attempted solution 2: Store return address in register
P: # Function P R: # Function R
movl $Rtn_point1, %eax …
jmp R # Call R jmp *%eax # Return
Rtn_point1:
…
Q: # Function Q
movl $Rtn_point2, %eax
Special form of jmp
jmp R # Call R
instruction; we will not use
Rtn_point2:
…
7
Q: # Function Q
movl $Rtn_point2, %eax
Problem if P calls Q, and Q
calls R
jmp R # Call R
Rtn_point2: Return address for P to Q
… call is lost
jmp %eax # Return
8
3
IA-32 Call and Ret Instructions
• Ret instruction “knows” the return address
P: # Function P R: # Function R
… …
1
call R ret
2
call Q
…
Q: # Function Q
…
call R
…
ret
10
11
Implementation of Call
• ESP (stack pointer register)
0
points to top of stack
ESP
12
4
Implementation of Call
• EIP (instruction pointer
0
register) points to next
instruction to be executed
Note: can’t really access EIP
Instruction
Effective Operations
directly, but this is implicitly
pushl src subl $4, %esp what call is doing
movl src, (%esp)
popl dest movl (%esp), dest
addl $4, %esp
call addr pushl %eip
jmp addr ESP
before
Call instruction pushes return call
address (old EIP) onto stack
13
Implementation of Call
0
Instruction
Effective Operations
14
Implementation of Ret
0
Instruction
Effective Operations
pushl src subl $4, %esp Note: can’t really access EIP
movl src, (%esp) directly, but this is implicitly
popl dest movl (%esp), dest
what ret is doing.
addl $4, %esp
call addr pushl %eip
jmp addr ESP Old EIP
ret pop %eip before
ret
Ret instruction pops stack, thus
placing return address (old EIP)
into EIP 15
5
Implementation of Ret
0
Instruction
Effective Operations
16
int f(void)
{
return add3(3, 4, 5);
}
17
18
6
Attempted Solution: Use Registers
• Problem: Cannot handle nested function calls
f: add3:
movl $3, %eax …
movl $4, %ebx movl $6, %eax
movl $5, %ecx call g
call add3 # Use EAX, EBX, ECX
… # But EAX is corrupted!
…
ret
ESP before
pushing
params
20
ESP Param 1
before Param …
call
Param N
21
7
IA-32 Parameter Passing
• Callee addresses params relative to 0
ESP: Param 1 as 4(%esp)
22
ESP Param 1
after Param …
return
Param N
23
ESP
after
popping
params
24
8
IA-32 Parameter Passing
For example:
f: add3:
… …
# Push parameters movl 4(%esp), wherever
pushl $5 movl 8(%esp), wherever
pushl $4 movl 12(%esp), wherever
pushl $3 …
call add3 ret
# Pop parameters
addl $12, %esp
25
EBP
26
Using EBP
• Need to save old value of EBP
• Before overwriting EBP register
0
EBP
27
9
Base Pointer Register: EBP
• Callee executes “prolog”
0
pushl %ebp
movl %esp, %ebp
28
29
30
10
Base Pointer Register: EBP
• Callee executes “epilog”
0
movl %ebp, %esp
popl %ebp
ret
EBP
31
ESP Param 1
Param …
Param N
EBP
32
int foo(void)
{
return add3(3, 4, 5);
}
33
11
IA-32 Solution: Use the Stack
• Local variables:
• Short-lived, so donʼt need a
permanent location in
memory
int add3(int a, int b, int c)
• Size known in advance, so {
int d;
donʼt need to allocate on the d = a + b + c;
heap
return d;
}
• So, the function just uses
int foo(void)
the top of the stack
{
• Store local variables on the return add3(3, 4, 5);
top of the stack
}
• The local variables disappear
after the function returns
34
add3:
…
# Allocate space for d
subl $4, %esp
…
# Access d
movl whatever, -4(%ebp)
…
ret
36
12
Problem 4: Handling Registers
• Problem: How do caller and callee functions use
same registers without interference?
• Registers are a finite resource!
• In principle: Each function should have its own set of
registers
• In reality: All functions must use the same small set of
registers
38
13
Problem 5: Return Values
• Problem: How does callee
function send return value
back to caller function?
int add3(int a, int b, int c)
• In principle:
{
int d;
• Store return value in stack d = a + b + c;
frame of caller
return d;
}
• Or, for efficiency:
int foo(void)
• Known small size => store {
return value in register
return add3(3, 4, 5);
• Other => store return value in }
stack
40
41
Stack Frames
Summary of IA-32 function handling:
• Stack has one stack frame per active function invocation
• ESP points to top (low memory) of current stack frame
• EBP points to bottom (high memory) of current stack
frame
• Stack frame contains:
• Return address (Old EIP)
• Old EBP
• Saved register values
• Local variables
• Parameters to be passed to callee function
42
14
A Simple Example
…
x = add3(3, 4, 5);
…
43
ESP
EBP
High memory 44
EBP
High memory 45
15
Trace of a Simple Example 3
x = add3(3, 4, 5); Low memory
EBP
High memory 46
EBP
High memory 47
EBP
High memory 48
16
Trace of a Simple Example 6
int add3(int a, int b, int c) { Low memory
int d;
d = a + b + c;
return d;
}
ESP Old EBP
# Save old EBP EBP Old EIP
pushl %ebp
# Change EBP Prolog 3
movl %esp, %ebp 4
5
Old EDX
Old ECX
Old EAX
High memory 49
High memory 50
High memory 51
17
Trace of a Simple Example 9
int add3(int a, int b, int c) { Low memory
int d; ESP 12
d = a + b + c; Old EDI
return d; Old ESI
} Old EBX
EBP Old EBP
# Save old EBP Old EIP
pushl %ebp
# Change EBP 3
movl %esp, %ebp 4
# Save caller-save registers if necessary 5
pushl %ebx
pushl %esi Old EDX
pushl %edi Old ECX
# Allocate space for local variable Old EAX
subl $4, %esp Access params as positive
# Perform the addition offsets relative to EBP
movl 8(%ebp), %eax
addl 12(%ebp), %eax Access local vars as negative
addl 16(%ebp), %eax
movl %eax, -16(%ebp) offsets relative to EBP
High memory 52
High memory 53
High memory 54
18
Trace of a Simple Example 12
int add3(int a, int b, int c) { Low memory
int d; 12
d = a + b + c; Old EDI
return d; Old ESI
} Old EBX
Old EBP
# Copy the return value to EAX ESP Old EIP
movl -16(%ebp), %eax
# Restore callee-save registers if necessary 3
movl -12(%ebp), %edi 4
movl -8(%ebp), %esi 5
movl -4(%ebp), %ebx
# Restore ESP Old EDX
movl %ebp, %esp Old ECX
# Restore EBP Epilog Old EAX
popl %ebp
EBP
High memory 55
EBP
High memory 56
EBP
High memory 57
19
Trace of a Simple Example 15
x = add3(3, 4, 5); Low memory
12
Old EDI
# Save caller-save registers if necessary
pushl %eax Old ESI
pushl %ecx Old EBX
pushl %edx Old EBP
# Push parameters
pushl $5 Old EIP
pushl $4 3
pushl $3 4
# Call add3
call add3 5
# Pop parameters ESP Old EDX
addl %12, %esp Old ECX
# Save return value
movl %eax, wherever Old EAX
EBP
High memory 58
20
Summary
• Calling and returning
• Call instruction: push EIP onto stack and jump
• Ret instruction: pop stack to EIP
• Passing parameters
• Caller pushes onto stack
• Callee accesses as positive offsets from EBP
• Caller pops from stack
61
Summary (cont.)
• Storing local variables
• Callee pushes on stack
• Callee accesses as negative offsets from EBP
• Callee pops from stack
• Handling registers
• Caller saves and restores EAX, ECX, EDX if necessary
• Callee saves and restores EBX, ESI, EDI if necessary
• Returning values
• Callee returns data of integral types and pointers in EAX
62
21