Reputation: 139
Suppose we are examining MIPS assembly code for a function f with only one local variable x:
void f(void) {
int x;
...
}
I have two questions:
What does the function prologue and epilogue for f do to the registers $sp, $ra and $fp assuming $ra and $fp are the only callee-saved registers modified by the function.
How does the MIPS assembly code for f accesses the variable x.
My attempt: The function prologue saves the registers $ra and $fp into the call stack. The function epilogue restores these registers by popping them off the stack, and returning control to the address in $ra. Not sure how MIPS can access the variable x, but I know local variables are also stored in the stack.
Upvotes: 4
Views: 6944
Reputation: 100
What does the function prologue and epilogue for f do to the registers $sp, $ra and $fp assuming $ra and $fp are the only callee-saved registers modified by the function.
$sp
- stack pointer
$fp
- frame pointer
$ra
- return address
The function prologue and epilogue refer to you saving the return address register (and any other registers as needed) to the stack at the beginning of the function and returning the values to their respective registers at the end of the function.
As you might have noticed, the MIPS arquitecture does not have a stack, you have to create it (you may want to check the manual for the simulator or specific processor you are using as the convened address for this varies).
You would save the address specified in the $sp in the main program:
daddi $sp, $sp, 0x400 # this is the convention address for WinMIPS64's stack
You may want to use the stack for several reasons, for instance:
$ra
) in case of nested functions$fp
, as per the question$s0-$s7
registers if you use them in a function. By convention these should always be saved to the stack when used (it's not applicable in this case, but someone else may be reading this, so).To do this you would use code as the user above did (code may vary slightly depending on which MIPS version you are using, check the manual).
To PUSH to the stack you must emulate stack function using code as per above (make space for data, save data on stack). Remember that when you PUSH to the stack as above, you must also POP the equal amount to return the $sp
to it's original position. You do this in the inverse order (again, as the user above shows).
Also: Because the call instruction for functions in MIPS (jal f - jump and link) saves the return address in a single register automatically ($ra
- return address, remember?), you always needs to do this if you are using recursion or if you are calling a second function from a first function, otherwise you lose your return address to the main program, because it will get "stepped on" by the next call.
$fp
, the frame pointer, would be used for instance if you have saved have many register values to the stack, and you would like to access the different operands without moving the $sp
which would remain pointing to the top of the stack. You would load the value of $sp
onto $fp
in order to do this, and then add a displacement value to move around.
It permits you to load values from the stack while keeping the $sp
in the same place, therefore permitting you to keep track of the push and pop operations.
How does the MIPS assembly code for f accesses the variable x.
By convention, MIPS has specific registers for arguments and for return values. In MIPS, arguments to be passed to the function are saved in registers $a0-$a3
, return values are saved in $v0-$v1
. Temporary registers which can be used within functions are $t0-$t9
but they do not preserver their value on return from function. However, as you may run out of registers, you may need to use the stack. By convention the $s0-$s7
are saved registers whose values are preserved by using the stack.
P.S. Important: I am using a WinMIPS64 simulator. MIPS assembly language varies in register size, instruction set & stack address, please reference your particular version manual and check which values apply in your case as this will affect your code.
Upvotes: 0
Reputation: 135
(a) What does the function prologue and epilogue for f do to the registers $sp, $ra and $fp assuming $ra and $fp are the only callee-saved registers modified by the function.
($fp is the 'frame pointer' also known as the 'base pointer', $sp is the 'stack pointer', and $ra is the 'return address')
To explain how 'int x' is accessed, it's important to know how and where it is stored. Since 'int x' is a local variable, MIPS will allocate the appropriate space (or if there is space use the method markgz was talking about) for the integer on the stack by subtracting the number of bytes (4) for the 32 bit integer from the stack pointer. The return address of the caller is also saved (another 4 bytes) so that the function can link back to the caller:
sub $sp, $sp, 8 #4 bytes for $ra + 4 bytes for 'int x' = 8 bytes allocated
sw $ra, 4($sp) #note the order, $ra is always first
sw [int x], 0($sp)
OR
addi $sp, $sp, -8 #an alternate to the code above
sw $ra, 4($sp)
sw [int x], 0($sp)
Likewise, at the end of the function call, the function will restore the registers to the caller by deallocating space on the stack:
lw [int x], 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
I don't have a lot of experience with using the frame pointer ($fp), but if the stack pointer ($sp) changes value during a procedure it can no longer be used as a reference point so the ($fp) takes it's place ($sp is just another register).
(b) How does the MIPS assembly code for f accesses the variable x.
To access 'int x', the function 'f' can load the variable into a temporary register.
lw $t0, 0($sp) #it can be any temporary register
Since local variables are not preserved across function calls, they can be stored in the temporary registers. Essentially the 'push' instruction would be 'sw' ('store word') and the 'pop' instruction would be 'lw' ('load word').
Also, I know MIPS can be a pain and this reference sheet really helped me out.
Upvotes: 5
Reputation: 6266
Take a look at the MIPS calling convention here. Typically a local variable in a function would be kept in a temporary (caller saved) register $t0 - $t9. If the function itself calls a function, local variables are saved on the stack.
There are no push
or pop
instructions in MIPS, so the function prologue decrements the stack pointer by enough words to allow for all of the stack storage needs of the function, and the function epilogue undoes this.
Upvotes: 0