Stack Frames and Procedure Calls

Stack Frames

To compile procedures, we organize stack into stack frames (activation records)

Each procedure call allocates new stack frame on the stack

When procedure returns, the stack frame is deallocated

This allows us to support recursive procedure calls

In addition to stack pointer SP, it is useful to have frame pointer

  • frame pointer points to beginning of stack data for current procedure
  • stack pointer points to (current) end of data

Stack pointer and frame pointer allow us to access data for procedure:

FP: local var 1
local var M
return address
temporary vars
saved registers
call argument N1
call argument 1
SP: (next frame)


void f(int x, int y) {
   int p;
   int q;
   q = 3;
   int tmp1; // temporary
   tmp1 = x + y;
   p = x1 + z;
-> g(p + 1, q);
int g(int a, int b) {
  int u, v;
  int tmp3;
  tmp3 = a + b;
  return tmp3;

Suppose that value of q is kept in register R5 and saved before the call. The stack then looks like this:

FP: p
R5 value (saved)
SP: (u will go here)
(v will go here)
no return addr (tmp3 will go here)

Calling Conventions

Hardware provides minimal support for procedure calls

One possibility is in Register Machine Model in Scala:

  • jsr saves pc+1 (i.e. pc+instructionLength) into special register e.g. R15
  • to return, jump to address in R15
  • for nested calls must first save R15 on stack

Calling convention of a programming language determines how calls are compiled

Many calling conventions possible

  • but caller (who calls) and callee (who is called) must agree
  • if different languages have same calling convention, programs can call each other's procedures

Example above illustrates one calling convention:

  • all parameters passed on stack (in specified order)
  • result passed on stack
  • a non-leaf procedure must save R15

Alternative: parameter and result passed in registers

  • must know in which register they are expected
  • if register has value useful for future, must save and restore its value around the call
  • register calling conventions speed-up leaf procedure calls

What determines the convention:

  • where is return address stored
  • where to store function arguments and results
  • does caller or callee save registers: caller-save and callee-save registers

Code for Return:

  • put result on stack or register (depending where it is assigned and on calling conventioon)
  • load return address from stack into R15 (unless we are leaf procedure)
  • jump to address in R15

Code for Call:

  • prepare parameters
  • jsr to address