x86 assembler call + return

advertisement
CS 201
Computer Systems Programming
Chapter 12
x86 Call & Return
Herbert G. Mayer, PSU
Status 6/28/2015
1
Syllabus








Motivation
Definitions
Stack Frame
Stack Operations
x86 Stack Operations
Masm PROC
Recursive Factorial in x86
References
2
Motivation
 Often not feasible to express complete assembler
program in a single file or as a single procedure
 Logical modules reduce complexity of human
programming task
 Allows re-use and reincarnation of the same
procedure through parameterization
 Higher Level concepts should hide detail of
call/return mechanism. For example, the low-level
manipulation of the stack through push and pop
and some detail or call and return operations
should be hidden
 However, some aspects of a context switch should
be reflected even in High Level language, in
particular the call and return itself
3
Definitions

Base Pointer: An address pointer (often implemented via a
dedicated register), that identifies an agreed-upon area in
the Stack Frame of an executing procedure. On the x86
architecture, this is implemented via the bp register

Binding: Procedures may have parameters. Formal
parameters express attributes such as type, name, and
similar attributes. At the place of call, often these formal
parameters receive initial, actual values through so-called
actual parameters. Sometimes, an actual parameter is solely
the address of the true object referenced during the call. The
association of actual to formal parameter is referred to as
parameter binding

Call: Transfer of control (a.k.a. context switch) to the
argument of the call instruction. A call expects that after
completion, the program resumes execution at the place
after the call instruction
4
Definitions

Dynamic Link: Element of Stack Marker, pointing to the Stack
Frame of the calling procedure. This caller is temporarily
dormant; i.e. it is the callée’s stack frame that is active. Since
the caller also has a Dynamic Link, all currently live Stack
Frames are linked together via this data structure

Frame Pointer: Synonym for Base Pointer; x86 uses bp
register

Pop: Stack operation that frees data from the stack. At times,
data are just popped because they are no longer needed, in
which case only the stack space is freed. This can also be
accomplished by changing the value of the stack pointer; on
x86 the sp register. Often the memory location is not
overwritten by a pop, i.e the data just stay. But the memory
area is not considered to be part of the active stack anymore

Push: Stack operation that reserves space on the stack.
Generally, the space reserved on the stack through a push is
initialized with the argument of the push operation. Other
times, a push just reserves space on the stack for data to be
initialized at a later time. On the x86 architecture a push
decreases the top of stack pointer (sp value)
5
Definitions

Return: Transfer of control after completion of a call.
Usually, this is accomplished through a return instruction.
The return instruction assumes the return address to the
code segment sits in a fixed part of the stack frame

Return Address: The code address to which execution will
switch once the call completes that activated the current
procedure

Return Value: The value returned by a function call. If the
return value is a composite data structure, then the location
set aside for the function return value is generally a pointer
to the actual data

Stack: Run time data structure that grows and shrinks
during program execution. It generally holds parameters,
locals, temps, plus control information (return addresses,
links). Operations that change the stack include push, pop,
call, return, and the like
6
Definitions

Stack Frame: Run time data structure associated with an
active procedure. A Stack Frame is composed of the
procedure parameters, the Stack Marker, local data, and
space for temporary data, including saved registers

Stack Marker: Run time data structure on the stack
associated with a Stack Frame. The Stack Marker holds fixed
information, whose structure is known a priori. This includes
the return address, the static link, and the dynamic link. In
some implementations, the Stack Marker also holds an entry
for the function return value and the saved registers

Stack Pointer: AKA top of stack pointer: A pointer (typically
implemented via a register) that addresses the last element
allocated (pushed) on top of the stack. On the x86
architecture this is implemented via the sp register. Other
architectures have the Stack Pointer refer to the next free
location (if any) on the stack
7
Definitions

Static Link: An address in the Stack Marker that points to the
Frame Pointer of the last invocation of the procedure, which
lexicographically surrounds the one executing currently.
This is necessary only for high level languages that allow
statically nested scopes, such as Ada, Algol, and Pascal.
This is not needed in more restricted languages such as C,
Java, or C++

Top of Stack: Stack location last allocated (pushed) object.
However, in some run-time systems the next free element is
called the top of stack
8
Stack Frame
The figure below shows a schematic layout of an abstract Stack
Frame. Some implementations have the stack grow toward higher,
others toward lower addresses. The scheme shown here does not
care; it just shows the general layout. Key points:
•
Stack Pointer identifies top of current stack, and also top of current Stack Frame
•
Stack pointer may vary often during invocation
•
Stack pointer changes upon call, return, push, pop, explicit assignments
•
Base pointer does not vary during call
•
Base pointer is set only once at start of call
•
Base pointer changed again at return, to value of previous base pointer, hence
the name dynamic link
•
Parameters are typically addressed relative to base pointer in one direction
•
Locals (and temps) can be addressed relative to base pointer in the other
direction
•
Possible to save base pointer, useful when registers are scarce, as on x86
•
However, this scheme is difficult, since compiler (or human programmer) must
keep dynamic size of stack in mind at any moment of time of code generation
9
Stack Frame
10
Stack Operations 32b
Before Call:
Push actual parameters: Changes the stack
Track size of actuals pushed
In many high-level languages the actual-parameter
size for a callée is fixed, as defined in the formal
parameter specification
Not so in C and C++ as it is allowed to pass a smaller
number of actual parameters than formally specified!!!
Base pointer bp (AKA frame pointer) still points to
Stack Marker of caller before the call is executed
When the last actual parameter has been pushed: one
flexible part of the Stack Frame is complete
11
Stack Operations 32b
Actual Call:
Push the instruction pointer (eip); in x86 done by
call instruction
eip already holds the address of the instruction
after the call; that is the return address
This slot on the stack identifies the beginning of the
Stack Marker
The call instruction also sets eip to the code
address of the destination (callée)
Original x86 architecture has 24 flavors of call
instructions
12
32bs
Stack
Operations 32b
Procedure Entry:
 Every time something is pushed or popped, the
Stack Pointer (esp) register changes
 Push the current value of the Base Pointer (ebp),
this is the dynamic link
 C needs no static link, has no nested functions
 Set Base Pointer to the value of the Stack Pointer;
e.g. mov ebp, esp
 Now the new Stack Frame is being addressed
 The fixed part of stack: Stack Marker is being built
 Allocate space for local variables, if any
 This establishes another area of the Stack Frame
that is variable in size
13
Stack Operations 32b
Return:
Pop locals and temps off stack
This frees the second flexible size area from the Stack Frame
Pop all registers to be restored back into those regs
Pop the top of stack value back into the ebp
This uses the Dynamic Link to reactivate the caller’s Stack Frame
Pop top of stack value into instruction pointer
This sets the eip register back to the instruction after the call
The return instruction does this
Either caller (or an argument of the return instruction on x86)
frees the space allocated for actual parameters
The x86 architecture allows an argument to the ret instruction,
freeing that amount of bytes off of the stack
14
0. x86 Stack Operations, small model
;Procedure Entry, No Locals, no saved Regs:
;
push
mov
Marker
; the call has taken place, and now:
bp
; save dyn link in Stack Marker
bp, sp ; establish new Frame: point to Stack
;Procedure Exit, No Locals, no Regs restored:
;
pop
ret
bp
0
; we are ready to “return”
; must find back old Stack Frame
; ip to instruction after call instruction
15
1. x86 Stack Operations, Save Regs
;Procedure Entry, No Locals, Save Regs ax and bx:
push
mov
Marker
push
push
bp
; save dyn link in Stack Marker
bp, sp ; establish new Frame: point to Stack
ax
bx
; save ax if needed by callée, optional
; ditto for bx
;Procedure Exit, No Locals, Restore Regs bx and ax:
pop
pop
pop
ret
bx
ax
bp
args
;
;
;
;
restore bx if was used by callée
ditto for ax
must find back old Stack Frame
ip to instruction after call; free args
16
2. x86 Stack Operations, Locals
;Procedure Entry With Locals, No Regs:
push
bp
; save dyn link in Stack Marker
mov
bp, sp ; establish new Frame: point to Stack
Marker
sub
sp, 24 ; allocate 24 bytes = 6 words for locals
;Procedure Exit With Locals, No Regs:
mov
pop
ret
sp, bp ; free all locals and temps
bp
; must find back old Stack Frame, RA on top
args
; ip to instruction after call; free args
17
3. x86 Stack Operations
;Procedure Entry With Locals, Save Regs:
push
bp
mov bp, sp
Marker
sub sp, 24
locals
push
ax
push
bx
; save dyn link in Stack Marker
; establish new Frame: point to Stack
; allocate 24 bytes un-init space for
; save ax if needed by callée, optional
; ditto for bx
;Procedure Exit With Locals, Restore Regs:
pop
pop
mov
pop
ret
bx
ax
sp, bp
bp
args
;
;
;
;
;
restore bx if was used by callée
ditto for ax
free all locals and temps
must find back old Stack Frame, RA on top
ip to instruction after call; free args
18
Masm PROC




A masm proc is a named short-hand for logical code module
Introduced by the proc keyword; proc is preceded by the
name of that procedure
Ended by the endp keyword; good to repeat the name of that
callable procedure
Pattern for proc without arguments, without return value is:
my_name
my_name

proc
push
mov
;
pop
ret
endp
bp
;
bp, sp ;
. . . now
bp
;
0
;
save dynamic link
new frame is addressed
your real code here
dynamic link of caller
clear 0 bytes off stack
And now my_name is callable, but no local space is
allocated, no parameters are passed, no function return
value is computed, no space needs to be freed at return
19
Masm PROC
 At the needed place in your code, an assembler
instruction call my_name now transfers control
to the procedure by that name
 And a ret instruction somewhere in procedure
my_name returns to the place after the call
 Best to package the sequence of procedural entry
instructions into a macro, specifically the push
and mov instructions
 And to package the procedure exit instructions
pop and ret into a macro, perhaps parameterized
with the number of bytes to be cleared off the
stack after the return
20
Recursive Factorial in x86
// Factorial first in C, x86 next
unsigned fact( unsigned arg )
{ // fact
if ( arg <= 1 ) {
return 1;
}else{
return fact( arg - 1 ) * arg;
} //end if
} //end fact
21
Recursive Factorial in x86, set up
penter
pexit
Errcode
MAX
arg
extrn
macro
;
push
bp
mov
bp, sp
push
bx
push
cx
push
dx
endm
; end of
macro args ;
pop
dx
pop
cx
pop
bx
pop
bp
ret
args
endm
; end of
=
4ch
=
9d
;
.model small
.stack 100h
.data
dw
0
.code
uPutDec : near
save all regs being used
penter
restore all saved regs
pexit
compute up to fact( 9 )
22
Recursive Factorial in x86, actual fact
; assume argument for recursive fact( arg ) on stack
; return fact( int arg ) in ax: 16 bit x86 mode
rfact proc
penter
mov
ax, [bp+4]; arg is 4 bytes b4 dyn link
cmp
ax, 1
; argument > 1?
jg
recurse
; if so: recursive call
base: mov
ax, 1
; No: then result known: 0!=1!=1
pexit 2
; and done, free 2 bytes = arg
recurse:
mov
ax, [bp+4]; need to recurse; get next arg
dec
ax
; but decrement first
push
ax
; and pass on stack
call
rfact
; recurse
mov
cx,[bp+4] ; partial product in ax, * arg
mul
cx
; product in ax
pexit 2
; and done
rfact endp
23
Recursive Factorial in x86, main
drive_r
proc
mov
mov
mov
arg, 0
ax, 0
bp, sp
; initial value again
again_r:
cmp arg,MAX
jge
done_r
;
ax holds arg to be factorialized :-)
push
ax
; argument on stack
call
rfact
done_r:
drive_r
;
call
inc
mov
jmp
ret
endp
now ax holds factorial value
uPutDec
arg
ax, arg
again_r
24
PutDec Macros
; Source File:
; Author:
; Date:
; Purpose:
;
Put_Ch MACRO
push
push
mov
mov
int
pop
pop
ENDM
putdec.asm
Herb Mayer
1/4/2001
print signed 16-bit number
PutDec is public
ch
; 'ch' char is printed
ax
; save, cos ax is overwritten
dx
; ditto for dx
dl, ch
; move into formal parameter
ah, 02h
; tell DOS who
021h
; call DOS
dx
; restore
ax
; ditto
Put_Str MACRO
push
push
mov
mov
int
pop
pop
ENDM
str_addr
; print string at 'str_addr'
ax
; save
dx
; save
dx, offset str_addr
ah, 09h
; DOS routine's id
021h
; call DOS
dx
; restore
ax
; ditto
25
PutDec Setup
base_10 =
.MODEL
.stack
.DATA
10
small
50
min_num db
'-32768$'
.CODE
public PutDec
; proc PutDec is called with argument in ax
; argument is the signed integer 16-bit number
; whose value is printed as decimal int #
26
PutDec Function
PutDec
PROC
;
cmp
jne
Put_Str
jmp
special case, -32768 cannot be negated
ax, -32768
; is it special case?
do_work
; nope! So do your job
min_num
; yep: so print it and be done
done
; and return to caller
push
push
push
push
;
cmp
jge
neg
Put_Ch
ax
bx
cx
dx
number in ax is NOT -32768; make positive
ax, 0
; negative number?
positive
; if not, invert sign and print ax
; here the inversion
'-'
; here the - printed
do_work:
27
PutDec Function
positive:
sub
cx, cx
; cx counts iterations = # digits
mov
bx, base_10
; base to be divided by
; now we know number in ax is non-negative
push_m:
sub
dx, dx
; make a double word
div
bx
; unsigned divide o.k.
add
dl, '0'
; make number a char
push
dx
; save it, cos order reversed
inc
cx
; count steps
cmp
ax, 0
; finally done?
jne
push_m
; if not, do next step
; now all chars are stored on stack in l-2-r order
pop_m:
pop
dx
; pop next into dx; dl really
Put_Ch dl
; print it as char
loop
pop_m
; more work? If so, do again
done:
pop
dx
pop
cx
pop
bx
pop
ax
ret
; return to caller
PutDec ENDP
END PutDec
28
References
1. Free masm download:
http://cvrce.blog.com/2009/08/28/masm-v611-freedownload/
2. http://www.emsps.com/oldtools/msasmv.htm
3. ML 64-bit: http://msdn.microsoft.com/enus/library/s0ksfwcf(v=vs.80).aspx
29
Download