EE209A - 24 16 AssemblyFunctions
EE209A - 24 16 AssemblyFunctions
Electrical Engineering
EE209: Programming Structures for Electrical Engineering
3
Function Call Problems
2. Passing parameters
• How does the caller function pass parameters to the callee function?
4. Handling registers
• How do the caller and callee functions use the same registers without
interference?
5. Returning a value
• How does the callee function send a return value back to the caller function?
4
Problem 1: Calling and Returning
How does the callee function jump back to the right place in the caller
function?
• i.e., Jump to the instruction immediately following the most-recently-
executed call instruction
5
Attempted Solution #1: Use Jmp Instruction
P: # Function P R: # Function R
… …
jmp R # Call R jmp Rtn_point1 # Return
Rtn_point1:
…
6
Attempted Solution #1: Use Jmp Instruction
P: # Function P R: # Function R
… …
jmp R # Call R jmp ??? # Return
Rtn_point1:
…
Q: # Function Q
…
jmp R # Call R
Rtn_point2:
…
7
Attempted Solution #2: Use Register
P: # Function P R: # Function R
…
movl $Rtn_point1, %eax
jmp *%eax # Return
jmp R # Call R
Rtn_point1:
…
Q: # Function Q
movl $Rtn_point2, %eax
Special form of jmp instruction;
jmp R # Call R we will not use
Rtn_point2:
…
8
Attempted Solution #2: Use Register
P: # Function P R: # Function R
Rtn_point1:
…
Q: # Function Q
Problem if P calls Q, and then Q calls R
movl $Rtn_point2, %eax
Return address for P to Q call is lost
jmp R # Call R
Rtn_point2:
…
jmp *%eax # Return
9
IA-32 Solution: Use the Stack
10
IA-32 Call and Ret Instructions
P: # Function P R: # Function R
…
… 1
ret
call R
2
call Q
…
Q: # Function Q
…
call R
…
ret
11
IA-32 Call and Ret Instructions
3 4 5
Q: # Function Q
…
call R
…
6
ret
12
Implementation of Call
ESP
13
Implementation of Call
14
Implementation of Call
15
Implementation of Ret
0
Instruction Effective Operations
pushl src subl $4, %esp Note: can’t really access EIP directly,
but this is implicitly what ret is doing
movl src, (%esp)
popl dest movl (%esp), dest
addl $4, %esp
call addr pushl %eip
jmp addr
ESP Old EIP
ret popl %eip before
ret
Ret instruction pops stack, thus placing
return address (old EIP) into EIP
16
Implementation of Ret
0
Instruction Effective Operations
pushl src subl $4, %esp
movl src, (%esp)
popl dest movl (%esp), dest
addl $4, %esp
call addr pushl %eip
jmp addr
ret popl %eip ESP
after
ret
17
Problem 2: Passing Parameters
int f(void)
{
return add3(3, 4, 5);
}
18
Attempted Solution: Use Registers
• Pass parameters in registers
f: add3:
movl $3, %eax …
movl $4, %ebx # Use EAX, EBX, ECX
movl $5, %ecx …
call add3 ret
…
19
Attempted Solution: Use Registers
20
IA-32 Solution: Use the Stack!
ESP
before
pushing
params
21
IA-32 Parameter Passing
ESP Param 1
before Param …
call
Param N
22
IA-32 Parameter Passing
• Callee addresses params relative to ESP: Param 1 as 4(%esp)
23
IA-32 Parameter Passing
• After returning to the caller…
0
ESP Param 1
after Param …
return
Param N
24
IA-32 Parameter Passing
ESP
after
popping
params
25
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
26
Base Pointer Register: EBP
• Problem:
• As the callee executes, ESP may change 0
• e.g., preparing to call another function
27
Using EBP
0
• Need to save old value of EBP
• Before overwriting EBP register
EBP
28
Base Pointer Register: EBP
0
• Callee executes “prolog”
• pushl %ebp
29
Base Pointer Register: EBP
0
• Before returning, callee must restore
ESP
ESP and EBP to their old values
30
Base Pointer Register: EBP
0
• Callee executes “epilog”
• movl %ebp, %esp
• popl %ebp
31
Base Pointer Register: EBP
0
• Callee executes “epilog”
• movl %ebp, %esp
• popl %ebp
• ret
EBP
32
Base Pointer Register: EBP
0
• Callee executes “epilog”
• movl %ebp, %esp
• popl %ebp
• ret
ESP Param 1
Param …
Param N
EBP
33
Problem 3: Storing Local Variables
int foo(void)
{
return add3(3, 4, 5);
}
34
IA-32 Solution: Use the Stack
• Local variables:
• Short-lived, so don’t need a
permanent location in memory
• Size known in advance, so don’t need int add3(int a, int b, int c)
{
to allocate on the heap int d;
d = a + b + c;
• The function simply uses the top of the return d;
stack }
35
IA-32 Local Variables
36
IA-32 Local Variables
For example:
add3:
…
# Allocate space for d
subl $4, %esp
…
# Access d
movl whatever, -4(%ebp)
…
ret
37
Problem 4: Handling Registers
• Problem: How do the caller and callee functions use the same
registers without interference?
• The callee might use the register the caller is also using
• When the callee returns control to the caller, old register contents
might be lost
• The caller function cannot continue where it left off
38
IA-32 Solution: Define a Convention
39
IA-32 Register Handling
0
• Caller-save registers
• EAX, ECX, EDX
• If necessary… ESP Var 2
• The caller saves on stack before call
Var 1
• The caller restores from stack after call Saved EBX,
ESI,EDI
40
Problem 5: Return Values
41
IA-32 Return Values
IA-32 Convention:
42
Stack Frames
• ESP points to the top (low memory) of the current stack frame
• Local variables
43
A Simple Example
…
x = add3(3, 4, 5);
…
44
Trace of a Simple Example 1
ESP
EBP
High memory
45
Trace of a Simple Example 2
EBP
High memory
46
Trace of a Simple Example 3
EBP
High memory
47
Trace of a Simple Example 4
EBP
High memory
48
Trace of a Simple Example 5
EBP
High memory
49
Trace of a Simple Example 6
High memory
50
Trace of a Simple Example 7
Low memory
int add3(int a, int b, int c) { ESP Old EDI
int d;
d = a + b + c; Old ESI
return d; Old EBX
} EBP Old EBP
Old EIP
# Save old EBP 3
pushl %ebp 4
# Change EBP
movl %esp, %ebp 5
# Save callee-save registers if necessary Old EDX
pushl %ebx Old ECX
pushl %esi Unnecessary here; add3 will not
pushl %edi change the values in these registers Old EAX
High memory
51
Trace of a Simple Example 8
Low memory
ESP
int add3(int a, int b, int c) { Old EDI
int d;
d = a + b + c; Old ESI
return d; Old EBX
} EBP Old EBP
Old EIP
# Save old EBP 3
pushl %ebp 4
# Change EBP
movl %esp, %ebp 5
# Save caller-save registers if necessary Old EDX
pushl %ebx Old ECX
pushl %esi
pushl %edi Old EAX
# Allocate space for local variable
subl $4, %esp
High memory
52
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
# Save old EBP EBP Old EBP
pushl %ebp Old EIP
# Change EBP 3
movl %esp, %ebp
# Save caller-save registers if necessary 4
pushl %ebx 5
pushl %esi Old EDX
pushl %edi
# Allocate space for local variable Old ECX
subl $4, %esp Access params as positive Old EAX
# 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
53
Trace of a Simple Example 10
High memory
54
Trace of a Simple Example 11
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
ESP Old EBP
# Copy the return value to EAX Old EIP
movl -16(%ebp), %eax EBP
# 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
Epilog Old EAX
High memory
55
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 Old EIP
movl -16(%ebp), %eax ESP
# 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
56
Trace of a Simple Example 13
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 Old EIP
movl -16(%ebp), %eax
# Restore callee-save registers if necessary ESP 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 Old EAX
popl %ebp
# Return to calling function
ret
EBP
High memory
57
Trace of a Simple Example 14
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
Old EAX
EBP
High memory
58
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
59
Trace of a Simple Example 16
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 Old EDX
addl %12, %esp Old ECX
# Save return value
movl %eax, wherever Old EAX
# Restore caller-save registers if necessary ESP
popl %edx
popl %ecx
popl %eax
EBP
High memory
60
Trace of a Simple Example 17
x = add3(3, 4, 5); Low memory
• Passing parameters
• Caller pushes onto stack
• Callee accesses as positive offsets from EBP
• Caller pops from stack
62
Summary (cont.)
• 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
63
64