Transcript Ch. I-8
CS2422 Assembly Language and System Programming
Advanced Procedures
Department of Computer Science
National Tsing Hua University
Assembly Language for IntelBased Computers, 5th Edition
CS2422 Assembly Language and System Programming
Kip Irvine
Chapter 8: Advanced Procedures
Slides prepared by the author
Revision date: June 4, 2006
(c) Pearson Education, 2006-2007. All rights reserved. You may modify and copy this slide show for your personal use,
or for use in the classroom, as long as this copyright statement, the author's name, and the title are not changed.
Chapter Overview
Stack Frames
Recursion
.MODEL Directive
INVOKE, ADDR, PROC, and PROTO
Creating Multimodule Programs
2
Two Ways to Pass Parameters
Register vs. stack parameters:
Register parameters require dedicating a register
to each parameter. Stack parameters are passed
through run-time stack
Registers are faster than stack
Ex: two ways of calling DumpMem; clearly the
second is easier to write
pushad
push OFFSET array
mov esi,OFFSET array
push LENGTHOF array
mov ecx,LENGTHOF array
push TYPE array
mov ebx,TYPE array
call DumpMem
call DumpMem
popad
3
How to Pass Stack Parameters?
Use stack frame (activation record)
Area of run-time stack that stores everything a
procedure needs in order to run, including return
address, passed parameters, saved registers, and
local variables state of the procedure
Each invocation to a procedure will push the
corresponding stack frame into the run-time stack
different invocations (even to the same
procedure) will occupy different areas of the stack
Procedure return will pop entire stack frame
Analog: mobile home
4
Contents of Stack Frame
What data are needed for the following function
to run?
int AddTwo(int x, y)
{
int sum;
sum = x + y;
return sum;
}
Parameters: x, y
Local variable: sum
Return address
Saved registers
“state”
x
y
return addr
sum
Size can be determined at assembly time
5
Accessing Stack Frame
When procedure AddTwo is called, its
corresponding stack frame is pushed onto the
run-time stack
How to reference the variables
in stack, i.e., x, y, sum?
AddTwo
mov
add
mov
ret
AddTwo
PROC
eax,x
eax,y
sum,eax
?
x
y
return addr
sum
ESP
ENDP
ESP?
6
Accessing Stack Frame
Idea: use addresses relative to a base address of
the stack frame in the run-time stack, which does
not change during the procedure
base pointer or frame pointer
Dedicate a register to hold this pointer EBP
A procedure can explicitly access stack
parameters using constant
offsets from EBP, e.g. [EBP + 8]
EBP is restored to its original
[EBP+12]
x
value when procedure returns
y
[EBP+8]
return addr [EBP+4]
sum
EBP*
* Exact location of frame pointer
will be explained shortly
7
Preparing Stack Frame
Must be done explicitly in the ASM program:
Caller procedure pushes arguments on the stack
and calls callee; the CALL instruction will push the
return address on the stack
Callee procedure pushes EBP (currently holding
frame point of the caller procedure) on the stack
‒ To save the EBP of the caller procedure
Callee then sets EBP to ESP
‒ To let EBP point to base of its own stack frame
If local variables are needed, a constant is
subtracted from ESP to make room on the stack
Net results: set aside a region of memory in stack
to hold all data needed for this procedure
8
Return from Procedure
RET: pops top of stack into the instruction pointer
(EIP or IP); control transfers to the target address
What about stack parameters?
Syntax:
RET
RET n
Optional operand n causes n bytes to be added to
the stack pointer after EIP (or IP) receives the
popped stack
9
Stack Frame Example
(1 of 2)
.data
sum DWORD ?
Return value in eax
.code
push 6
; second argument
push 5
; first argument
call AddTwo
; EAX = sum
mov sum,eax
; save the sum
AddTwo PROC
push ebp
mov ebp,esp
.
.
00000006
[EBP + 12]
00000005
[EBP + 8]
return address
[EBP + 4]
oldEBP
EBP
EBP, ESP
10
Stack Frame Example
(2 of 2)
00000006
[EBP + 12]
00000005
[EBP + 8]
return address
[EBP + 4]
oldEBP
EBP
EBP, ESP
AddTwo PROC
push ebp
mov ebp,esp
; base of stack frame
mov eax,[ebp + 12]; second argument (6)
add eax,[ebp + 8] ; first argument (5)
pop ebp
ret 8
; clean up the stack
AddTwo ENDP
; EAX contains the sum
11
Passing Arguments by Reference
(1/2)
Consider the ArrayFill procedure, which fills an
array with 16-bit random integers
Calling procedure passes address of the array,
along with a count of number of array elements:
.data
count = 100
array WORD count DUP(?)
.code
push OFFSET array
push COUNT
call ArrayFill
...
12
Passing Arguments by Reference
(2/2)
ArrayFill can reference an array without knowing
the array's name:
ArrayFill PROC
push ebp
mov ebp,esp
pushad
mov esi,[ebp+12]
mov ecx,[ebp+8]
...
offset(array)
[EBP + 12]
count
[EBP + 8]
return address
EBP
EBP
ESI points to the beginning of the array, so it's
easy to use a loop to access each array element
13
Local Variables
To explicitly create local variables, subtract their
total size from ESP to leave space
Still part of the stack frame
Ex.: creates and initializes two 32-bit local
variables (locA and locB):
MySub PROC
push ebp
mov ebp,esp
sub esp,8
; make space
mov DWORD PTR [ebp-4],123456h
; locA
mov DWORD PTR [ebp-8],0
; locB
...
14
Clean Local Variables on Return
Before return, resets ESP by assigning it the
value of EBP
release local variables from the stack
MySub PROC
push ebp
mov ebp,esp
sub esp,8
mov DWORD PTR [ebp-4],123456h
mov DWORD PTR [ebp-8],0
mov esp,ebp
pop ebp
ret
MySub ENDP
; locA
; locB
15
ENTER and LEAVE
ENTER directive creates stack frame for a called
procedure
ENTER numbytes, nestinglevel
pushes EBP on the stack
sets EBP to the base of the stack frame
reserves space for local variables
LEAVE: reverse operations
MySub PROC
enter 8,0
MySub PROC
push ebp
mov
ebp,esp
sub
esp,8
16
LOCAL Directive
A local variable is created, used, and destroyed
within a single procedure
LOCAL directive declares a list of local variables
LOCAL varlist
immediately follows the PROC directive
each variable is assigned a type
MySub PROC
LOCAL var1:BYTE, var2:WORD, var3:SDWORD
17
Using LOCAL
Examples:
myProc PROC,
LOCAL t1:BYTE,
; procedure
; local variables
LOCAL flagVals[20]:BYTE
; array of bytes
LOCAL pArray:PTR WORD ; pointer to an array
18
MASM-Generated Code (1/2)
BubbleSort PROC
LOCAL temp:DWORD, SwapFlag:BYTE
. . .
ret
BubbleSort ENDP
BubbleSort PROC
push ebp
mov ebp,esp
add esp,0FFFFFFF8h ; add -8 to ESP
. . .
mov esp,ebp
pop ebp
ret
BubbleSort ENDP
19
MASM-Generated Code (2/2)
Diagram of the stack frame for BubbleSort:
return address
EBP
ESP
EBP
temp
[EBP - 4]
SwapFlag
[EBP - 8]
20
Non-Doubleword Local Variables
Local variables can have different sizes
How are their memory space allocated in the
stack by LOCAL directive?
8-bit: assigned to next available byte
16-bit: assigned to next even (word) boundary
32-bit: assigned to next doubleword boundary
21
Local Byte Variable
Example1 PROC
LOCAL var1:BYTE
mov al,var1
ret
Example1 ENDP
; [EBP - 1]
22
LEA Instruction
Return offsets of direct and indirect operands
OFFSET can only return constant offsets
LEA required when obtaining the offset of a stack
parameter or local variable. For example:
void CopyString(int *count)
{
char temp[20];
...
}
CopyString PROC,
count:DWORD
;
LOCAL temp[20]:BYTE ;
mov edi,OFFSET count;
mov esi,OFFSET temp ;
lea edi,count
;
lea esi,temp
;
parameter
local variable
invalid operand
invalid operand
ok
ok
23
Review
1.
2.
3.
4.
5.
6.
7.
(True/False): A procedure’s stack frame always contains
caller’s return address and procedure’s local variables.
(True/False): Arrays are passed by reference to avoid
copying them onto the stack.
(True/False): A procedure’s prologue code always pushes
EBP on the stack.
(True/False): Local variables are created by adding an
integer to the stack pointer.
(True/False): In 32-bit protected mode, the last parameter
to be pushed on the stack in a procedure call is stored at
location EBP+8.
(True/False): Passing by reference requires popping a
parameter’s offset from the stack in the called procedure.
What are two common types of parameters?
24
What's Next
Stack Frames
Recursion
.MODEL Directive
INVOKE, ADDR, PROC, and PROTO
Creating Multimodule Programs
25
What is Recursion?
The process created when . . .
A procedure calls itself
Procedure A calls procedure B, which in turn calls
procedure A
Using a graph in which each node is a procedure
and each edge is a procedure call, recursion
forms a cycle:
A
E
B
D
C
26
Recursively Calculating a Sum
Recursively calculates sum of array of integers.
Receives: ECX = count. Returns: EAX = sum
CalcSum PROC
cmp ecx,0
jz L2
add eax,ecx
dec ecx
call CalcSum
L2: ret
CalcSum ENDP
;
;
;
;
;
check counter value
quit if zero
otherwise, add to sum
decrement counter
recursive call
Stack frame:
27
Calculating a Factorial (1/3)
This function calculates the factorial of integer n.
A new value of n is saved in each stack frame:
int factorial(int n) {
if(n == 0)
return 1;
else
return n*factorial(n-1);
}
recursive calls
backing up
5! = 5 * 4!
5 * 24 = 120
4! = 4 * 3!
4 * 6 = 24
3! = 3 * 2!
3*2=6
2! = 2 * 1!
2*1=2
1! = 1 * 0!
1*1=1
0! = 1
1 =281
(base case)
Calculating a Factorial (2/3)
Factorial PROC
push ebp
mov ebp,esp
mov eax,[ebp+8]
; get n
cmp eax,0
; n < 0?
ja
L1
; yes: continue
mov eax,1
; no: return 1
jmp L2
L1: dec eax
push eax
; Factorial(n-1)
call Factorial
; Instructions from this point on execute when
; each recursive call returns.
ReturnFact:
mov ebx,[ebp+8]
; get n
mul ebx
; eax = eax * ebx
L2: pop ebp
; return EAX
ret 4
; clean up stack
Factorial ENDP
29
Calculating a Factorial (3/3)
Suppose we want to
calculate 12!
This diagram shows the first
few stack frames created by
recursive calls to Factorial
Each recursive call uses 12
bytes of stack space.
12
n
ReturnMain
ebp0
11
n-1
ReturnFact
ebp1
10
n-2
ReturnFact
ebp2
9
n-3
ReturnFact
ebp3
(etc...)
30
What's Next
Stack Frames
Recursion
.MODEL Directive
INVOKE, ADDR, PROC, and PROTO
Creating Multimodule Programs
31
INVOKE Directive
The INVOKE directive is a powerful replacement
for Intel’s CALL instruction that lets you pass
multiple arguments
Syntax:
INVOKE procedureName [, argumentList]
Arguments can be:
immediate values and integer expressions
variable names
address and ADDR expressions
register names
32
INVOKE Examples
.data
byteVal BYTE 10
wordVal WORD 1000h
.code
; direct operands:
INVOKE Sub1,byteVal,wordVal
; address of variable:
INVOKE Sub2,ADDR byteVal
; register name, integer expression:
INVOKE Sub3,eax,(10 * 20)
; address expression (indirect operand):
INVOKE Sub4,[ebx]
33
ADDR Operator
Returns a near or far pointer to a variable,
depending on which memory model your
program uses:
Small model: returns 16-bit offset
Large model: returns 32-bit segment/offset
Flat model: returns 32-bit offset
Simple example:
.data
myWord WORD ?
.code
INVOKE mySub,ADDR myWord
34
PROC Directive (1/2)
The PROC directive declares a procedure with
an optional list of parameters.
Syntax:
label PROC paramList
paramList is a list of parameters separated by
commas. Each parameter has the following
syntax:
paramName:type
type must either be one of the standard ASM
types (BYTE, SBYTE, WORD, etc.), or it can be
a pointer to one of these types.
35
PROC Directive (2/2)
Alternate format permits parameter list to be on
one or more separate lines:
label PROC,
paramList
comma required
The parameters can be on the same line . . .
param-1:type-1, param-2:type-2, ...
Or they can be on separate lines:
param-1:type-1,
param-2:type-2,
. . .,
param-n:type-n
36
Sanity Check #1
Remember that PROC and INVOKE are
directives, not instructions.
(i.e., CPU does not understand it.)
37
PROC Examples (1/2)
The AddTwo procedure receives two integers
and returns their sum in EAX
C++ programs typically return 32-bit integers
from functions in EAX
AddTwo PROC,
val1:DWORD, val2:DWORD
mov eax,val1
add eax,val2
ret
AddTwo ENDP
38
PROC Examples (2/2)
FillArray receives a pointer to an array of bytes, a
single byte fill value that will be copied to each
element of the array, and the size of the array.
FillArray PROC,
pArray:PTR BYTE, fillVal:BYTE
arraySize:DWORD
mov ecx,arraySize
mov esi,pArray
mov al,fillVal
L1:mov [esi],al
inc esi
loop L1
ret
FillArray ENDP
39
PROTO Directive
Creates a procedure prototype
Syntax:
label
PROTO
paramList
Every procedure called by the INVOKE directive
must have a prototype
A complete procedure definition can also serve
as its own prototype
Example: Prototype for the ArraySum procedure,
showing its parameter list
ArraySum PROTO,
ptrArray:PTR DWORD,
szArray:DWORD
40
PROTO Directive
Standard configuration:
PROTO appears at top of the program listing,
INVOKE appears in the code segment, and the
procedure implementation occurs later in the
program:
MySub PROTO
; procedure prototype
.code
INVOKE MySub
; procedure call
MySub PROC
; procedure implementation
.
.
MySub ENDP
41
Sanity Check #2
So, PROC and INVOKE are directives, not
instruction.
How does MASM handle the parameters?
42
Passing by Value
When a procedure argument is passed by value,
a copy of a 16-bit or 32-bit integer is pushed on
the stack. Example:
.data
myData WORD 1000h
.code
main PROC
INVOKE Sub1, myData
MASM generates the following code:
push myData
call Sub1
43
Passing by Reference
When an argument is passed by reference, its
address is pushed on the stack. Example:
.data
myData WORD 1000h
.code
main PROC
INVOKE Sub1, ADDR myData
MASM generates the following code:
push OFFSET myData
call Sub1
44
Example: Exchanging Two Integers
Swap procedure exchanges the values of two 32bit integers. pValX and pValY do not change
values, but the integers they point to are modified.
Swap PROC USES eax esi edi,
pValX:PTR DWORD, ; pointer to 1st int
pValY:PTR DWORD
; pointer to 2nd int
mov esi,pValX
; get pointers
mov edi,pValY
mov eax,[esi]
; get first integer
xchg eax,[edi]
; exchange with second
mov [esi],eax
; replace first integer
ret
Swap ENDP
45
Example: Exchanging Two Integers
Will the following work?
Swap PROC USES eax esi edi,
X:DWORD,
Y:DWORD
mov eax, X
xchg eax, Y
mov X,eax
ret
Swap ENDP
; get first integer
; exchange with second
; replace first integer
A DWORD 10
B DWROD 20
INVOKE Swap A, B
INVOKE Swap ADDR A, ADDR B ;for previous slide
46
Trouble-Shooting Tips
Save and restore registers when they are
modified by a procedure.
When using INVOKE, be careful to pass a
pointer to the correct data type.
Except a register that returns a function result
For example, MASM cannot distinguish between a
DWORD argument and a PTR BYTE argument.
Do not pass an immediate value to a procedure
that expects a reference parameter.
Dereferencing its address will likely cause a
general-protection fault.
47
Summary
Stack parameters
Local variables
more convenient than register parameters
passed by value or reference
ENTER and LEAVE instructions
created on the stack below stack pointer
LOCAL directive
Recursive procedure calls itself
MASM procedure-related directives
INVOKE, PROC, PROTO
48