190 likes | 299 Views
Implementing Procedures. Computer Organization and Assembly Language: Module 8. Simple procedures. To implement a procedure which acts only on global data, and which doesn’t call any other procedures, we need only remember the address of the instruction after the procedure call.
E N D
Implementing Procedures Computer Organization and Assembly Language: Module 8
Simple procedures • To implement a procedure which acts only on global data, and which doesn’t call any other procedures, we need only remember the address of the instruction after the procedure call Calling procedureCalled procedure la $t0, after1 b procedure after1: … la $t0, after2 b procedure after2: procedure: … jr $t0 # jr is jump register
Simple procedures • However, this is not generally desirable because • It is not sufficient to implement recursive functions • It requires that local data for each function be memory resident at all times Calling procedureCalled procedure la $t0, after1 b procedure after1: … la $t0, after2 b procedure after2: procedure: … jr $t0 # jr is jump register
Supporting general procedures • Prologue • place parameters in a place where the called procedure can access them • transfer control to the called procedure • Save return address (on stack) • acquire local data storage (on stack) • Body (where the work gets done) • Epilogue • place results in a place accessible to the calling procedure • release local data storage • return control to the point of origin in the calling procedure calling system stack called
Registers & Instructions for Procedures • Registers • $a0-$a3:to pass parameters • $v0-$v1:for return value • $ra: return address • Instructions • jal (jump and link) : jumps to an address and saves the address of the next instruction in $ra • jr (jump register) $ra is used to return from • A register other than $ra may be specified
The system stack • A stack is so frequently used for procedure call/return, that many computer systems define a system stack. • The system stack is for dynamic data (vs static, knownbefore runtime) • Return addresses • Saving registers to move other data into register bank (“spilling”) • Local variables • The system stack can be very large • In a multi-user environment, how many system stacks are needed?
Local variables and the stack • Variables local to a procedure disappear when it returns • Most local variables are bound to registers • What if we run out of registers? • The “extra” locals are stored on the system stack • Top pointed to by $sp • Not space above stack • grows downward in memory foo: sub $sp,$sp,160 #(4*40) lw $t0, 112($sp) #c=$t0 ... add $sp, $sp, 160 jr $ra void foo ( ) {int a[40]; c = a[28]; … return;}
Memory in spim • The first 64M of memory is reserved, invalid • This is for error detection • User code is loaded from 0x00400000 to 0x0ffffffc • User data is stored from 0x10000000 to 0x7fffeffc • The kernel code and data is loaded above 0x8000000 0xffffffff 0x80000000 0x10000000 0x00400000 0x00000000 kernel stack code
MIPS ALU registers Value is always zero Used by the assembler Return values from functions Pass parameters to functions (caller saved) ` Caller saved register Callee saved registers More caller saved registers Used by the kernel (operating system) Global pointer Stack pointer Frame pointer Return address (used by JAL instruction)
$sp Subroutine caller bar(int a) { ... j=1+ifoo(3 + a); ... } #a is bound to $a0 #j is bound to $s0 … add $a0, $a0, 3 add $sp, $sp, -4 sw $t1, 0($sp) jal ifoo lw $t1, 0($sp) add $sp, $sp, 4 add $s0, $v0, 1 … Stack $t1
$sp Subroutine callee Stack ifoo(int a) { ... return a*ibar(a); } #assume use of $s0 sw $ra, -4($sp) sw $s0, -8($sp) add $sp, $sp, -8 … jal ibar mul $v0,$a0,$v0; lw $ra, 4($sp) lw $s0, 0($sp) add $sp, $sp, 8 jr $ra $t1 $ra $s0
Stack frames • Compilers for high level languages use a standard template for storage of registers, parameters, and local variables • Registers bound variables also have space in the frame • This collection of data to be pushed onto the stack for each procedure call is known as a stack frame • Also called an activation record • Appendix A.6 describes the standard MIPS frame • gcc uses a different structure
Steps for making a procedure call • If used, the values in $t0-$t9 are pushed onto the stack • If needed after the call, the values in $a0-$a3 are pushed onto the stack • Pass arguments • The first 4 arguments are passed in $a0-$a3 • Additional arguments are pushed onto the stack in reverse order
$fp $sp Prologue to a procedure • Push callee-saved registers onto the stack • $s0-$s7, if used • $fp • $ra, if the procedure makes a procedure call • Push space for local variables onto the stack • Update $fp and $sp registers • $fp = old $sp - 4 • $sp = old $sp - frame size Stack Frame 1
$fp $sp Prologue to a procedure • Push callee-saved registers onto the stack • $s0-$s7, if used • $fp • $ra, if the procedure makes a procedure call • Push space for local variables onto the stack • Update $fp and $sp registers • $fp = old $sp - 4 • $sp = old $sp - frame size Stack Frame 1 Frame 2
$fp $sp Prologue to a procedure • Push callee-saved registers onto the stack • $s0-$s7, if used • $fp • $ra, if the procedure makes a procedure call • Push space for local variables onto the stack • Update $fp and $sp registers • $fp = old $sp - 4 • $sp = old $sp - frame size Stack Frame 1 Frame 2
$fp $sp Prologue to a procedure • Push callee-saved registers onto the stack • $s0-$s7, if used • $fp • $ra, if the procedure makes a procedure call • Push space for local variables onto the stack • Update $fp and $sp registers • $fp = old $sp - 4 • $sp = old $sp - frame size Stack Frame 1 Frame 2
While a procedure is running • The local variables of the procedure are referenced by using the constant offset from the frame pointer (if they are not bound to registers) • Before making a procedure call, local variables bound to caller saved registers can be saved into the frame to preserve their values • This is necessary with recursive calls • The stack pointer may move during the call to handle expression evaluation or procedure calls • The frame pointer will not move
Epilogue to a procedure • Put the return value in $v0 • Restore callee-saved registers from the frame • This includes $fp and $ra • Pop the frame from the stack by adding frame size to the stack pointer • Return to caller by jumping to the address in $ra