0% found this document useful (0 votes)
11 views64 pages

EE209A - 24 16 AssemblyFunctions

Uploaded by

김문엽
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views64 pages

EE209A - 24 16 AssemblyFunctions

Uploaded by

김문엽
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 64

EE209: Programming Structures for

Electrical Engineering
EE209: Programming Structures for Electrical Engineering

Lecture 14: Assembly


Language: Function Calls
Goals of this Lecture

• Help you learn:


• Function call problems:
• Calling and returning
• Passing parameters
• Storing local variables
• Handling registers without interference
• Returning values
• IA-32 solutions to those problems
• Pertinent instructions and conventions

3
Function Call Problems

1. Calling and returning


• How does the caller function jump to the callee function?
• How does the callee function jump back to the right place in the caller function?

2. Passing parameters
• How does the caller function pass parameters to the callee function?

3. Storing local variables


• Where does the callee function store its local variables?

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 caller function jump to the callee function?


• i.e., Jump to the address of the callee’s first instruction

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

• The caller and callee use the 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

• Problem: the callee might be called by multiple callers

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

• Store the return address in a 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

• Problem: Cannot handle nested function calls

P: # Function P R: # Function R

movl $Rtn_point1, %eax …


jmp *%eax # Return
jmp Q # Call Q

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

• May need to store many return addresses


• The number of nested functions is not known in advance
• A return address must be saved for as long as the function invocation
continues, and discarded thereafter

• Addresses used in reverse order


• e.g., function P calls Q, which then calls R
• Then R returns to Q which then returns to P
EIP for Q
• Last-In-First-Out data structure (stack!!!)
EIP for P
• Caller pushes the return address on the stack
• … and callee pops the return address off the stack

• IA 32 solution: use the stack via call and ret

10
IA-32 Call and Ret Instructions

• ret instruction “knows” the return address

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

• Ret instruction “knows” the return address


P: # Function P R: # Function R
… …
call R
ret
call Q

3 4 5
Q: # Function Q

call R

6
ret

12
Implementation of Call

• ESP (stack pointer register) points to top of stack


0

Instruction Effective Operations


pushl src subl $4, %esp
movl src, (%esp)
popl dest movl (%esp), dest
addl $4, %esp

ESP

13
Implementation of Call

• EIP (instruction pointer register) points to next instruction to be executed


0

Note: can’t really access EIP directly,


but this is implicitly what call is doing
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 ESP
before
Call instruction pushes return address call
(old EIP) onto stack

14
Implementation of Call

Instruction Effective Operations


pushl src subl $4, %esp
movl src, (%esp)
popl dest movl (%esp), dest
addl $4, %esp
ESP Old EIP
call addr pushl %eip
after
jmp addr
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

• Problem: How does the caller function pass parameters to the


callee function?
int add3(int a, int b, int c)
{
int d;
d = a + b + c;
return d;
}

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

• 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

• Also: How to pass parameters that are longer than 4 bytes?

20
IA-32 Solution: Use the Stack!

• Caller pushes parameters before executing the call instruction


0

ESP
before
pushing
params

21
IA-32 Parameter Passing

• Caller pushes parameters in the reverse order


• Push Nth param first 0
• Push 1st param last
• So first param is at top of
the stack at the time of the call

ESP Param 1
before Param …
call
Param N

22
IA-32 Parameter Passing
• Callee addresses params relative to ESP: Param 1 as 4(%esp)

ESP Old EIP


after Param 1
call
Param …
Param N

23
IA-32 Parameter Passing
• After returning to the caller…
0

ESP Param 1
after Param …
return
Param N

24
IA-32 Parameter Passing

• … the caller pops the parameters from the stack


0

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

• Error-prone for the callee to reference


the parameters as the offsets relative to
ESP

ESP Old EIP


• Solution: after Param 1
call
• Use EBP as fixed reference point to Param …
access parameters Param N
• Base Pointer: think EBP as the start
address of the new stack
EBP

27
Using EBP

0
• Need to save old value of EBP
• Before overwriting EBP register

• Callee executes “prolog” ESP Old EBP


• pushl %ebp Old EIP
• movl %esp, %ebp Param 1
Param …
Param N

EBP

28
Base Pointer Register: EBP

0
• Callee executes “prolog”
• pushl %ebp

• movl %esp, %ebp

ESP,EBP Old EBP


• Regardless of ESP, the callee can Old EIP
reference param 1 as 8(%ebp), param Param 1
2 as 12(%ebp), etc. Param …
Param N

29
Base Pointer Register: EBP

0
• Before returning, callee must restore
ESP
ESP and EBP to their old values

• Callee executes “epilog” EBP Old EBP


• movl %ebp, %esp Old EIP
• popl %ebp Param 1
• ret Param …
Param N

30
Base Pointer Register: EBP

0
• Callee executes “epilog”
• movl %ebp, %esp
• popl %ebp

• ret Old EBP


ESP,
EBP Old EIP
Param 1
Param …
Param N

31
Base Pointer Register: EBP

0
• Callee executes “epilog”
• movl %ebp, %esp
• popl %ebp

• ret

ESP Old EIP


Param 1
Param …
Param N

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

• Where does the callee store its local variables?

int add3(int a, int b, int c)


{
int d;
d = a + b + c;
return d;
}

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 }

• Store local variables on the top of the int foo(void)


stack {
return add3(3, 4, 5);
• The local variables disappear after the }
function returns

35
IA-32 Local Variables

• Local variables of the callee are


allocated on the stack 0
• Allocation done by moving the stack
ESP Var 2
pointer
Var 1
• Example: allocate memory for two EBP Old EBP
integers
Old EIP
• subl $4, %esp
Param 1
• subl $4, %esp Param …
• (or equivalently, subl $8, %esp) Param N
• Reference local variables as negative
offsets relative to EBP
• -4(%ebp)
• -8(%ebp)

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?

• 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

• 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

• IA-32 solution: save the registers on the stack


• Someone must save old register contents
• Someone must later restore the register contents

• Define a convention for who saves and restores which


registers

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

• Callee-save registers EBP Old EBP


• EBX, ESI, EDI Old EIP
• If necessary… Param 1
• The callee saves on stack after prolog Param …
• The callee restores from stack before epilog Param N
• The caller can assume that values in EBX, ESI, EDI will not be Saved EAX,
changed by the callee
ECX,EDX
• 40

40
Problem 5: Return Values

• Problem: How does the callee function


send the return value back to the caller
function?
int add3(int a, int b, int c)
• In principle: {
int d;
• Store the return value in stack frame of d = a + b + c;
caller return d;
}
• Or, for efficiency:
int foo(void)
• Known small size  store return value {
in register return add3(3, 4, 5);
}
• Others  store return value in stack

41
IA-32 Return Values

IA-32 Convention:

• Integral type or pointer:


• Store return value in EAX
int add3(int a, int b, int c)
• char, short, int, long, pointer
{
• Floating-point type: int d;
d = a + b + c;
• Store return value in floating-point return d;
}
register
• (Beyond scope of course) int foo(void)
{
• Structure: return add3(3, 4, 5);
}
• Store return value on stack
• (Beyond scope of course)

42
Stack Frames

Summary of IA-32 function handling:

• Stack has one stack frame per active function invocation

• ESP points to the top (low memory) of the current stack frame

• EBP points to the bottom (high memory) of current stack frame

• Stack frame contains:


• Old EBP

• Saved register values

• Local variables

• Parameters to be passed to the callee function

• Return address (Old EIP)

43
A Simple Example

int add3(int a, int b, int c)


{
int d;
d = a + b + c;
return d;
}

/* In some calling function */


x = add3(3, 4, 5);

44
Trace of a Simple Example 1

x = add3(3, 4, 5); Low memory

ESP

EBP
High memory
45
Trace of a Simple Example 2

x = add3(3, 4, 5); Low memory

# Save caller-save registers if necessary


pushl %eax
pushl %ecx
pushl %edx
ESP Old EDX
Old ECX
Old EAX

EBP
High memory
46
Trace of a Simple Example 3

x = add3(3, 4, 5); Low memory

# Save caller-save registers if necessary 3


pushl %eax ESP
pushl %ecx 4
pushl %edx 5
# Push parameters Old EDX
pushl $5
pushl $4 Old ECX
pushl $3 Old EAX

EBP
High memory
47
Trace of a Simple Example 4

x = add3(3, 4, 5); Low memory

ESP Old EIP


# Save caller-save registers if necessary 3
pushl %eax
pushl %ecx 4
pushl %edx 5
# Push parameters Old EDX
pushl $5
pushl $4 Old ECX
pushl $3 Old EAX
# Call add3
call add3

EBP
High memory
48
Trace of a Simple Example 5

int add3(int a, int b, int c) { Low memory


int d;
d = a + b + c;
return d;
} ESP Old EBP
Old EIP
# Save old EBP 3
pushl %ebp 4
Prolog
5
Old EDX
Old ECX
Old EAX

EBP
High memory
49
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
EBP Old EIP
# Save old EBP 3
pushl %ebp 4
# Change EBP Prolog
movl %esp, %ebp 5
Old EDX
Old ECX
Old EAX

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

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
# Copy the return value to EAX 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
Old EDX
Old ECX
Old EAX

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

# Save caller-save registers if necessary


pushl %eax
pushl %ecx
pushl %edx
# Push parameters
pushl $5
pushl $4
pushl $3
# Call add3
call add3
# Pop parameters
addl %12, %esp
# Save return value
movl %eax, wherever
# Restore caller-save registers if necessary ESP
popl %edx
popl %ecx
popl %eax
# Proceed! EBP

High memory
61
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

62
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

63
64

You might also like