The following was the way I was taught to call functions in MIPS in school. I was simply told to "memorize" the "prologue" and the "epilogue", but never explained its concept. Here it is:
First, initialize $sp, the stack pointer. Then call jal f:
li $sp, 0x7ffffffc
jal f # call function f
When inside the function, first do the "prologue":
sub $sp, $sp, 8 # set new stack pointer
sw $ra, 8($sp) # save return address in stack
sw $fp, 4($sp) # save old frame pointer in stack
add $fp, $sp, 8 # set new frame pointer
When returning, do the "epilogue":
lw $ra, 8($sp) # load return address from stack
lw $fp, 4($sp) # restore old frame pointer from stack
add $sp, $sp, 8 # reset stack pointer
jr $ra # return to caller using saved return address
Question:
The values stored inside $ra never changed (unless my functions used it, but I shouldn't be using $ra in the first place). The prologue just saved it inside the stack, and restored the same value back into $ra when returning. jr is acting upon the same thing, so why is storing $ra in the stack necessary in the first place? And why do I need to restore it back if it never changed?
It makes sense to store $fp inside the stack because $fp was changed. But $ra is just the same returning address. Is the processor looking through the stack to match the values inside $ra with ones on the stack?