How compilers handle procedure calls
This note describes how the high-level abstraction of the procedure call is implemented in Assembly, as handled by the compiler.
When a procedure is called, we jump to the section of the code which contains the procedure body.
We use a stack to hold activation records which hold:
- input arguments
- the return address of the caller
- the results of the procedure computation
- saved values of registers
Each time a procedure is called, a new activation record is pushed onto the stack.
The stack exists in memory. We reserve some registers to make procedure calls and using the stack easier:
- SP - the stack pointer points to the top of the stack
- LP - linkage pointer which is the location of the caller in the program
- BP - the base pointer points to the location of the current activation record. This is a convenience, we can do everything relative to the SP, but as the stack grows and shrinks, this can be hard to think about.
The caller:
- pushes arguments onto the stack
- saves the current program counter to the LP
- branches to the callee
- after the callee finishes, deallocate the activation record
The callee:
- does the computation, accessing the arguments in the activation record as needed, and allocating local storage on the stack as needed
- puts the result in register 0
- branches to the return address