Understanding Stacks and Stack Frames

A stack is a region of memory used to represent the state of function calls, including local variables, return addresses and values that must be preserved across calls. The specific portion of memory on the stack that is allocated for a single function call is known as a stack frame/activation record.


In MIPS, the stack is at the top of the user address space and it grows downwards from high-end memory to low-end memory.

  • Pushing : adding an item onto the stack, decreasing the address of the stack pointer (sp)</p></li><li><p><strong>Popping</strong>:removinganitemfromthestack,increasingtheaddressofthestackpointer(adjustthepointerbacktothepreviousitem)</p></li></ul><p></p><p>Managingastackrequirestwoprimaryregisters:</p><ul><li><p><strong>StackPointer(sp)</p></li><li><p><strong>Popping </strong>: removing an item from the stack, increasing the address of the stack pointer (adjust the pointer back to the previous item)</p></li></ul><p></p><p>Managing a stack requires two primary registers:</p><ul><li><p><strong>Stack Pointer(sp) : Keeps track of the current top of the stack. Moves constantly/moving target

  • Frame Pointer(fp)</strong>:Marksthebaseorstartofthecurrentstackframe.Fixedforafunction/anchor</p></li></ul><p></p><p>Atypical<strong>stackframe</strong>containsthefollowinginformationtoensurethefunctioncanexecuteandreturncorrectly:</p><ul><li><p><strong>ReturnAddress(fp) </strong>: Marks the base or start of the current stack frame. Fixed for a function/anchor</p></li></ul><p></p><p>A typical <strong>stack frame </strong>contains the following information to ensure the function can execute and return correctly:</p><ul><li><p><strong>Return Address(ra) : Stored immediately upon entry if the function is an interior function (one that calls other functions )

  • Saved Registers ($s0 - $s7) : Any saved registers that the function intends to use must have their original values saved to the frame and restored before the function returns

  • Local variables : Space for variables that only exist while he function is active

  • Parameters : If the function has more than four arguments, the extras that do not fit in the registers $a0 - $a3 are passed via the stack

  • Register Spill Space: Extra memory used to store register values if the CPU runs out of available registers during complex calculations.


The creation and destruction of a stack frame follow a strict convention between the caller (the code making the call) and the callee (the function being called)

1. Call Setup (Caller and Callee):

  • The caller passes the first four arguments in a0–a0–a3 and pushes any additional arguments onto the stack.

  • The callee allocates the frame by saving the old frame pointer, setting the new frame pointer to the current sp</code><span>,andthensubtractingtherequirednumberofbytesfrom</span><code>sp</code><span>, and then subtracting the required number of bytes from </span><code>sp to create the frame space.

2. Function Return (Callee):

  • The callee places the return value in v0–v0–v1.

  • It restores the stack pointer by setting it to the frame pointer (or adding the frame size back to $sp).

  • It restores the previous frame pointer and the return address from the stack before jumping back to the caller using jr $ra.


The stack frame is an essential convention that allows functions to operate independently, managing their own data and remembering where to return, regardless of how many other functions are called in the process.


A Stack fram exists because every function needs its own private workspace. If two functions shared memory, everything would overwrite everything else. Therefore:

  • each call → new frame

  • stack grows → new memory reserved

  • function returns → memory removed


For saved registers, if your function uses $s0, you must:

sw $s0, ...

and then later:

lw $s0, ...


You need a stack frame if a function calls other functions (non leaf), if you use $s registers and if you need local variables. You wouldnt need it otherwise if it was a leaf function and everything could fit in the $t registers


The lifecycle of Stacks

To setup a stack:

addi $sp, $sp, -N
sw $ra, ...
sw $fp, ...
move $fp, $sp

and then do the body which is the logic and maybe some function calls.

and then:

move $sp, $fp
lw $fp, ...
lw $ra, ...
jr ra</code></pre><p></p><h4id="2ff0696e−dcd5−4c7b−9195−b55d5279cdc4"data−toc−id="2ff0696e−dcd5−4c7b−9195−b55d5279cdc4"collapsed="false"seolevelmigrated="true">StackFrameSize</h4><p>whencountingstackframesize,youonlytakenoteof:</p><ul><li><p>ra</code></pre><p></p><h4 id="2ff0696e-dcd5-4c7b-9195-b55d5279cdc4" data-toc-id="2ff0696e-dcd5-4c7b-9195-b55d5279cdc4" collapsed="false" seolevelmigrated="true">Stack Frame Size</h4><p>when counting stack frame size, you only take note of:</p><ul><li><p>ra


  • fp</p></li><li><p>fp</p></li><li><p>s registers used

  • local variable

  • we never count $t registers unless explicitly stated