This page is going to talk about using subroutine structures in MIPS Assembly. Also, this page will talk about some of the common methods by which higher-level language constructs and subroutines are translated into MIPS assembly code.
In MIPS, the general purpose registers are typically taken to be the function parameters and the function variables, as needed. Previous values of the general purpose registers are stored on the stack. At the end of a subroutine, the values of all registers stored in this manner are restored from the stack.
MIPS uses the stack to preserve these registers. The stack pointer points to the bottom of the stack, but the frame pointer points to the top of the local frame. Offsetting from the stack or frame pointers can retrieve the various saved values and function parameters, as needed.
Stem and Leaf
In the function hierarchy, a function that calls other functions is known as a stem function. A function which calls no other functions is known as a leaf function. Stem functions must save the value of $ra on the stack, so that its content is preserved across the other function calls, and so the called function can return to the calling function, or its parent function.
It is important to note that a leaf function does not need to preserve the value of the $ra register because it does not call any other child function and hence its return address is preserved in $ra.
A function may set up a stack frame, with the $sp register pointing to the bottom of the stack, and the $fp register pointing to the top of the stack at the start of the subroutine. In this manner, $fp will be pointing to the function's input arguments (if any are on the stack), and $sp will be pointing to the local variables for the function.
The value of $fp needs to be preserved across function calls, and stem functions need to save the value of $fp before calling a child function, and restore it from the stack after calling the child function.
The value of $sp does not need to be stored on the stack, but functions need to take care to return $sp to the value it had at the beginning of the function, before the function returns. This means that at the beginning of a subroutine, values can be pushed onto the stack, and at the end of the subroutine, all those values need to be popped right back off the stack. If this is not done correctly, it will destroy the stack frame of the parent function, and possibly cause the computer to crash.
There are a number of registers that must be preserved across a subroutine call. This means that if the subroutine wants to use those registers, it must save the previous values onto the stack (or some other place), and then reload those values at the end of the function. The $tx registers are all temporary registers and do not need to be saved. Likewise, the $ax registers are all function arguments, and do not need to be saved. Thr $v0 and $v1 registers are both function return values, and do not need to be saved.
The following registers do need to be preserved across a function call, and should be saved by the function if they are going to be used in the function:
- The "Saved Temporary" registers