Move the mouse down the code to see the stack change
space for $ra | (unused) | |
a | local vars | |
b | of fun3 | |
$sp-> | space for arguments | |
to fun3 |
fun3: sub $sp, 24 sw $ra, 20($sp) sw $fp, 16($sp) move $fp, $sp sw $a0, 24($fp) sw $a1, 28($fp) li $a0, 5 li $a1, 7 jal fun1 .... fun1: sub $sp, 16 sw $fp, 8($sp) move $fp, $sp sw $a0, 16($fp) #args to fun1 sw $a1, 20($fp) li $2, 7 #local i sw $2, 0($fp) li $2, 9 #local j sw $2, 4($fp) ... # Back from fun1, store result in a sw $v0, 8($fp)
You have just seen an animation of some MIPS code produced by a "real compiler" from C. This code is found on pp. 100-103 in "Introduction to RISC Assembly Language Programming" by John Waldron, Addison-Wesley, 1999. It shows the use of the stack as each function moves the stack pointer, saves the frame pointer value, and then moves the frame pointer. On return, the saved value of frame pointer is restored. Please note that the functions "don't do anything useful," they just illustrate how the compiler uses the stack to save the registers $ra and $fp, and provide storage for arguments and local variables.
Just like our arms evolved from fins, when we swam in water, where they weren't attached to our skeletons, - Compilers evolved in an environment with very few registers, so they evolved a stack structure in which calling a function proceeded as follows: