Why we need to use the runtime stack to store parameters and local variables
 

  • A non-leaf subroutine will call another subroutine

  • Therefore: parameters and local variables stored inside registers will get overwritten by a subroutine call:

       NonLeafSub:
      
          ...  r0, r1, r2, ... contain important values
          ...
          bl  anotherSub   // r0, r1, r2, ... may be overwritten  
          ...
      

    We must use the runtime stack to store the parameters and local variables !

Stack frame: data structure used to store a subroutine's parameters and local variables
 

The data structure used to store a (non-leaf) subroutine's parameters and local variables is the stack frame (or activation record):

The FP register contains the base address to a stack frame object

A field (= a parameter or a local variable) stored inside the stack frame object is accessed using a offset from the base address in the FP register

How to call a non-leaf subroutine (that needs to store parameters on the runtime stack)
 

How to call a (non-leaf) subroutine with k parameters:

     // Push the parameters on the stack
     load  parameter k into r0            
     push  {r0}
     load  parameter k-1 into r0
     push  {r0}
     ....
     load  parameter 2 into r0            
     push  {r0}
     load  parameter 1 into r0
     push  {r0}

     bl    Subroutine   // Call the subroutine

     // Pop the parameters off the stack
     add   sp, sp,  #4×k  // Clean up k int parameters 
   

The structure of a (non-leaf) subroutine
 

The structure of a (non-leaf) subroutine that has n local variables

  Subroutine:
     // Prelude
     push    {lr}         // Save return addr
     push    {fp}	  // Save caller's FP reg
     mov     fp, sp	  // Establish the base address
     sub     sp, sp, #4n  // Allocate n local variables

     ...
     ...  // Body of the subroutine
     ...

     put the return value in the return location (usually r0)

     // Postlude
     mov    sp, fp        // De-allocates the local variables   
     pop    {fp}	  // Restore the saved FP value
     pop    {pc}	  // Return to the caller