CS 322
HM
COMPILER DESIGN
HO 3.2
PSU
(4/26/2010)
Motivation: High level programming requires logical (and physical) modularization . The key tool for logical modularization is the creation of procedures (in some languages called s ubroutines ) and functions with their associated call, parameters, and return. This handout introduces call and return for the Intel x86 architecture, AKA IA-32 architecture.
Note that we’ll use the term procedure generically to mean either procedure, function or subroutine, unless the particular meaning of one is needed, in which case that is spelled out. Let’s start with 1.) a few definitions. Then we’ll outline simple stack operations in 2.) and refine with 3.) sample x86 code sequences to accomplish these operations. We conclude with 4.) the implementation of a recursive factorial() function in x86.
Base Pointer:
A pointer, often implemented via a dedicated register, that addresses an agreed upon area in the S tack
Frame of the currently executing procedure. On the x86 architecture this is implemented via the bp register.
Binding:
Procedures may have parameters. Formal parameters express a template for each parameter, including type, name, and similar attributes. At the place of call, these formal parameters receive initial, actual values, even if this is just the address of the corresponding actual parameter to be set later during the call. This association of actual to formal parameter is referred to as binding.
Call:
Transfer of control (aka context switch ) to the operand of the call with the expectation, that after completion of the call execution will resume at the place after the call instruction.
Dynamic Link:
A location in the Stack Marker that points to the Stack Frame of the procedure which called the currently active one.
Frame Pointer:
Synonym for Base Pointer.
Pop:
Stack operation that frees data from the stack. Often, the data popped off are assigned to some other object. Other 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.
Push:
Stack operation that reserves temporary 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
1
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
PSU space on the stack for data to be initialized at a later time. Note that on the x86 architecture a push decreases the top of stack pointer (sp value).
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 be saved in a fixed part of the stack frame , called the Stack Marker .
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 data information (parameters, locals, temps) and control information (return addresses, links). Operations that change the stack include push, pop, call, return , and the like
Stack Frame:
Run time data structure associated with an active procedure (or function). A Stack Frame is composed of the procedure parameters , the Stack Marker , local data , and space for temporary data, including saved registers . 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; AKA frame pointer
Base pointer only set up once at start of call
Base pointer changed again at return, to value of previous base pointer, dynamic link
Parameters can be 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; not discussed here
2
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
PSU sp
Locals + Temps bp
Stack Marker
Actual Parameters
Stack Frame
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:
A.k.a 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. It is also possible to have the Stack Pointer refer to the next free location (if any) on the stack in case another push operation needs stack space.
Static Link:
Address in the Stack Marker that identifies the Stack Frame of the last invocation of the procedure which lexicographically surrounds the currently executing one. This is implemented only in high level languages that allow nested scopes, such as Ada and Pascal; not needed in simpler languages like C.
Top Of Stack:
Stack location last allocated (pushed).
3
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
PSU
Before Call:
Push actual parameter
Changes the stack
Track size of actuals pushed
In most languages the actual size is fixed; not so in C
Base pointer still points to Stack Marker of caller
After last actual parameter pushed: one flexible part of Stack Frame complete
Call:
Push instruction pointer (ip)
Note that ip points to target of call, not the instruction after call;
however, address of instruction after call must be saved as return address
This identifies the beginning of the Stack Marker
Set the instruction pointer to the address of the destination
Note that x86 architecture has 24 flavors of call instruction
Procedure Entry:
Push Base Pointer , this is the dynamic link
Set Base Pointer to value of Stack Pointer
Now the new Stack Frame is being addressed
The fixed part of stack, the 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
Return:
Pop locals and temps off stack
This frees the second variable size area from the Stack Frame
Pop registers to be restored
Pop the top of stack value into the base pointer bp
This uses the Dynamic Link to reactivate the previous Stack Frame
Pop top of stack value into instruction pointer
This sets the ip register back to the instruction after the call
The return instruction does this
Either caller (or a suitable argument of the return instruction) frees the space allocated for actual parameters
4
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
Procedure Entry, No Locals, Save Regs push bp ; save dyn link in Stack Marker mov bp, sp push ax push bx
; establish new Frame: point to Stack Marker
; save ax if needed by callee, optional
; ditto for bx
PROCEDURE EXIT, NO LOCALS, RESTORE REGS pop bx pop ax pop bp ret args
; restore bx if was used by callee
; ditto for ax
; must find back old Stack Frame
; ip to instruction after call; free args
PROCEDURE ENTRY WITH LOCALS, NO REGS push bp mov bp, sp sub sp, 24
; save dyn link in Stack Marker
; establish new Frame: point to Stack Marker
; allocate 24 bytes uninit. space for locals
PROCEDURE EXIT WITH LOCALS, NO REGS mov sp, bp pop bp ret args
; free all locals and temps
; must find back old Stack Frame, RA on top
; ip to instruction after call; free args
PROCEDURE ENTRY WITH LOCALS, SAVE REGS push bp mov bp, sp sub sp, 24 push ax push bx
; save dyn link in Stack Marker
; establish new Frame: point to Stack Marker
; allocate 24 bytes uninit. space for locals
; save ax if needed by callee, optional
; ditto for bx
PROCEDURE EXIT WITH LOCALS, RESTORE REGS pop bx pop ax mov sp, bp pop bp ret args
; restore bx if was used by callee
; ditto for ax
; free all locals and temps
; must find back old Stack Frame, RA on top
; ip to instruction after call; free args
PSU
5
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
FACTORIAL IN C unsigned fact( unsigned arg )
{ // fact if ( arg <= 1 ) { return 1;
}else{ return fact( arg - 1 ) * arg;
} //end if
} //end fact
FACTORIAL IN X86 ASSEMBLER
; Source file: fact.asm
. . . penter macro push bp mov bp, sp push bx push cx push dx endm pexit macro args pop dx pop cx pop bx pop bp ret args endm
Errcode =
MAX =
4ch
9d
.model small
.stack 100h arg
.data dw 0
.code extrn uPutDec : near rfact proc
; assume argument for recursive fact( arg ) on stack
; return fact( int arg ) in ax
PSU
6
HO 3.2
CS 322
HM
COMPILER DESIGN
HO 3.2
PSU base: penter mov ax, [bp+4] ; argument sits 4 bytes b4 dyn link cmp ax, 1 ; argument > 1? jg recurse ; if so: recusive call mov ax, 1 pexit 2
; No: then result known: 0!=1!=1
; and done recurse: mov ax, [bp+4] ; need to recurse; get next arg dec ax ; but decrement first push ax call rfact
; and pass on stack
; recurse rfact mov cx, [bp+4] ; partial product in ax, * arg mul cx ; product in ax pexit 2 endp drive_r proc
; and done again_r: mov arg, 0 mov ax, 0 mov bp, sp
; initial value again cmp arg, MAX jge done_r
; ax holds argument to be factorialized :-) push ax ; argument on stack call rfact
; now ax holds factorial value call uPutDec inc arg mov ax, arg jmp again_r done_r: ret drive_r endp
7
HO 3.2