1 EE 109 Unit 16 – Stack Frames
2 Arguments and Return Values Number Name Purpose • MIPS convention is to $0 $zero Constant 0 $1 $at Assembler temporary use certain registers for (psuedo-instrucs.) this task $2-$3 $v0-$v1 Return value ($v1 only used for dword) – $a0 - $a3 used to pass $4-$7 $a0-$a3 Arguments (first 4 of a up to 4 arguments. If subroutine) more arguments, use the $8-$15, $t0-$t9 Temporary registers $24,$25 stack – $v0 used for return value $16-$23 $s0-$s7 Saved registers $26-$27 $k0-$k1 Kernel reserved • Only 1 return value but it $28 $gp Global pointer (static global may be a double-word data var’s .) (64-bits) in which case $29 $sp Stack pointer $v1 will also be used $30 $fp Frame pointer $31 $ra Return address
3 Arguments and Return Values void main() { ... int ans,arg1,arg2; MAIN: la $s0, arg1 # Get addr. ans = avg(arg1, arg2); la $s1, arg2 # of arg1/arg2 lw $a0, 0($s0) # Get val. of } lw $a1, 0($s1) # arg1/arg2 jal AVG # call function la $s2, ans int avg(int a, int b) { sw $v0, ($s2) # store ans. int temp=1; // local var’s ... return a+b >> temp; AVG: li $t0, 1 # temp=1 } add $v0,$a0,$a1 # do a+b srav $v0,$v0,$t0 # do shift jr $ra C Code Equivalent Assembly
4 Assembly & HLL’s • When coding in assembly, a programmer can optimize usage of registers and store only what is needed to memory/stack – Can pass additional arguments in registers (beyond $a0-$a3) – Can allocate variables to registers (not use memory) – Can handle spilling registers to memory only when necessary • When coding in an HLL & using a compiler, certain conventions are followed that may lead to heavier usage of the stack and memory – We have to be careful not to overwrite registers that have useful data
5 Compiler Handling of Subroutines • High level languages (HLL) use the stack: – to save register values including the return address – to pass additional arguments to a subroutine – for storage of local variables declared in the subroutine • Compilers usually put data on the stack in a certain order, which we call a stack "frame" • To access this data on the stack a pointer called the "frame pointer" ($30=$fp) is often used in addition to the normal stack pointer ($sp)
6 Stack Frame Motivation • Assume the following C code • Now assume each function was written by a different programmer on their own (w/o talking to each other) • What could go wrong? int x=5, nums[10]; int main() { caller(x, nums); return 0; } int caller(int z, int* dat) { int a = dat[0]-1; return callee(5)+a+z; } int callee(int val) { return (val+3)/2; }
7 Stack Frame Motivation int x=5, nums[10]; int main() { caller(x, nums); return 0; } • The caller needs to ensure the int caller(int z, int* dat) { int a = dat[0]-1; callee routine does not return callee(5)+a+z; } overwrite a needed register int callee(int val) { return (val+3)/2; } 1. Caller may have his own .text arguments in $a0-$a3 and then MAIN: la $t0,x need to call a subroutine and lw $a0,0($t0) Loaded into $a0 la $a1,NUMS New Value use $a0-$a3 jal CALLER ... CALLER: lw $s0, 0($a1) addi $s0,$s0,-1 li $a0, 5 1 jal CALLEE add $v0,$v0,$s0 add $v0,$v0,$a0 1 But old value needed here jr $ra CALLEE: addi $s0,$a0,3 sra $v0,$s0,1 jr $ra
8 Stack Frame Motivation int x=5, nums[10]; int main() { caller(x, nums); return 0; } • The caller needs to ensure the int caller(int z, int* dat) { int a = dat[0]-1; callee routine does not return callee(5)+a+z; } overwrite a needed register int callee(int val) { return (val+3)/2; } 1. Caller may have his own .text arguments in $a0-$a3 and then MAIN: la $t0,x need to call a subroutine and lw $a0,0($t0) la $a1,NUMS use $a0-$a3 jal CALLER 2 ... 2. Return address ($ra) [We've CALLER: lw $s0, 0($a1) addi $s0,$s0,-1 already seen this problem] li $a0, 5 jal CALLEE 2 add $v0,$v0,$s0 add $v0,$v0,$a0 jr $ra 2 CALLEE: addi $s0,$a0,3 sra $v0,$s0,1 jr $ra
9 Stack Frame Motivation int x=5, nums[10]; int main() { caller(x, nums); return 0; } • The caller needs to ensure the int caller(int z, int* dat) { int a = dat[0]-1; callee routine does not return callee(5)+a+z; } overwrite a needed register int callee(int val) { return (val+3)/2; } 1. Caller may have his own will cause CALLER to overwrites $s0 which .text Callee unknowingly arguments in $a0-$a3 and then MAIN: la $t0,x malfunction need to call a subroutine and lw $a0,0($t0) la $a1,NUMS use $a0-$a3 jal CALLER ... 2. Return address ($ra) CALLER: lw $s0, 0($a1) 3 addi $s0,$s0,-1 3. Register values calculated before li $a0, 5 jal CALLEE the call but used after the call add $v0,$v0,$s0 3 add $v0,$v0,$a0 (e.g. $s0) jr $ra CALLEE: addi $s0,$a0,3 3 sra $v0,$s0,1 jr $ra
10 Solution • If you're not sure whether some .text MAIN: la $t0,x lw $a0,0($t0) other subroutine is using a la $a1,NUMS jal CALLER register (and needs it later)… ... CALLER: addi $sp,$sp,-4 • Save (push) it to the stack Save $ra sw $ra, 0($sp) before you overwrite it lw $s0, 0($a1) addi $s0,$s0,-1 – Recall a push: addi $sp,$sp,-4 Save $a0 addi $sp, $sp, -4 sw $a0,0($sp) sw reg_to_save , 0($sp) li $a0, 5 jal CALLEE • Restore (pop) it from the stack lw $a0, 0($sp) Restore before you return addi $sp,$sp,4 $a0 add $v0,$v0,$s0 – Recall a pop: add $v0,$v0,$a0 lw $ra, 0($sp) lw reg_to_restore , 0($sp) Restore addi $sp,$sp,4 $ra jr $ra addi $sp, $sp, 4
11 Solution • If you're not sure whether .text MAIN: la $t0,x some other subroutine is using lw $a0,0($t0) la $a1,NUMS a register (and needs it later)… jal CALLER ... CALLER: addi $sp,$sp,-4 1 $sp 0000 0000 7fffeffc 7fffeffc sw $ra, 0($sp) 0000 0000 7fffeff8 $ra 0040208c 1 lw $s0, 0($a1) 0000 0000 7fffeff4 $a0 addi $s0,$s0,-1 10001230 At start of caller() addi $sp,$sp,-4 sw $a0,0($sp) 0000 0000 7fffeffc $sp 7fffeff4 0040 208c 7fffeff8 2 $ra 2 0040208c li $a0, 5 1000 1230 7fffeff4 jal CALLEE $a0 00000005 Before 'jal CALLEE' instruction lw $a0, 0($sp) addi $sp,$sp,4 0000 0000 7fffeffc add $v0,$v0,$s0 $sp 7fffeffc add $v0,$v0,$a0 3 0040 208c 7fffeff8 $ra 0040208c lw $ra, 0($sp) 1000 1230 7fffeff4 addi $sp,$sp,4 $a0 3 10001230 jr $ra Before 'jr $ra'
12 Local Variables • A functions local variables are also allocated on the stack void main() { MAIN: addi $sp, $sp, -4 // Allocate 3 integers sw $ra, 0($sp) # save $ra int ans, arg1=5, arg2=7; # Now allocate 3 integers ans = avg(arg1, arg2); addi $sp, $sp, -12 } // vars. deallocated here li $t0, 5 sw $t0, 4($sp) C Code li $t0, 7 sw $t0, 8($sp) $sp 0000 0000 7fffeffc 7fffeffc lw $a0, 4($sp) # Get val. of Saved $ra 7fffeff8 lw $a1, 8($sp) # arg1/arg2 arg2=7 7fffeff4 jal AVG # call function arg1=5 7fffeff0 sw $v0, 0($sp) # store ans. ... ans 7fffefec $sp 7fffefec # deallocate local vars addi $sp,$sp,12 lw $ra, 0($sp) addi $sp,$sp,4 jr $ra Equivalent Assembly
13 Local Variables • Locally declared arrays are also allocated on the stack • Be careful : variables and arrays often must start on well-defined address boundaries void main() { MAIN: addi $sp, $sp, -4 char mystr[14] = "hello..."; sw $ra, 0($sp) # save $ra double z; # Now allocate array addi $sp, $sp, -16 # not -14 C Code } # May pad to get to 8-byte # boundary.. $sp 0000 0000 7fffeffc 7fffeffc Saved $ra 7fffeff8 # now alloc. z pad mystr[13-12] 7fffeff4 addi $sp, $sp, -8 mystr[11-8] 7fffeff0 # deallocate local vars 7fffefec mystr[7-4] o addi $sp,$sp,24 mystr[3-0] l l e h 7fffefe8 lw $ra, 0($sp) addi $sp,$sp,4 z 7fffefe4 jr $ra z 7fffefe0 $sp 7fffefe0 Equivalent Assembly
14 Stack Frames • Frame = Def: All data on stack belonging to a subroutine/function – Space for arguments (in addition to $a0-$a3) Local Vars. – Space for saved registers ($fp, $s0-$s7, $ra) (ans, x, y) – Space for local variables (those declared in a Saved Regs. Main Routine’s function) Subroutine’s Stack Frame arguments (copy of x,y) Local Vars. void main() { (temp) int ans, x, y; ... Saved Regs. Subroutines ans = avg(x, y); ($ra,$fp, Stack Frame } others) int avg(int a, int b) { Sub- subr’s int temp=1; // local var’s arguments Stack Growth ... Stack Frame } Organization
15 Accessing Values on the Stack • Stack pointer ($sp) is usually used to Local Vars. Func1 frame access only the top value on the stack (ans) • To access arguments and local variables, Saved Regs. we need to access values buried in the stack Args. – We can simply use an offset from $sp [ 8($sp) ] Local Vars. Func2 frame (temp) • Unfortunately other push operations by Saved Regs. the function may change the $sp requiring ($ra,$fp, different displacements at different times + offset others) for the same variable $sp Args. • This can work, but can be confusing $sp lw $t0, 16 ($sp) # access var. x To access parameters we could addi $sp,$sp,-4 # $sp changes try to use some displacement [i.e. sw $t0, 20 ($sp) # access x with d($sp) ] but if $sp changes, must # diff. displacement use new d value
Recommend
More recommend