So it is very efficient to store local variables on the stack because the order in which the subroutines become active/inactive is FILO - exactly what a stack does.
main: int A[10]; int sum; sum = ArraySum(A, 10); |
int ArraySum(int A[], int n) { int i, s; // Local variables s = 0; for (i = 0; i < n; i++) s = s + A[i]; return (s); } |
main: move.l #A, -(a7) * Pass address of array A move.l #10, -(a7) * Pass # elements in array bsr ArraySum adda.l #8, a7 * remove (pop) #A and #10 from stack move.l d0, sum * put return value in variable "sum" |
+---------------+ | free space | +---------------+ <----- a7 (stack pointer) 0(a7) | return address| +---------------+ 4(a7) | n (#10) | +---------------+ 8(a7) | A (#A) | +---------------+ | ..... | |
The subroutine returns the value in register D0.
ArraySum: suba.l #8, a7 * Create 2 local variables on stack !!! * Note: NOW the stack is: * * Offsets * +---------------+ <----- a7 (stack pointer) * 0(a7) | s | (you decide which location is s and i) * +---------------+ * 4(a7) | i | (This program uses s and i in the given manner) * +---------------+ * 8(a7) | return address| * +---------------+ * 12(a7) | n (10) | * +---------------+ * 16(a7) | A (#A) | * +---------------+ move.l #0, 0(a7) * s = 0 move.l #0, 4(a7) * i = 0 While: move.l 4(a7), d0 * puts local variable i in d0 move.l 12(a7), d1 * puts parameter n in d1 cmp.l d1, d0 BGE WhileEnd * Exit while loop if i >= n * ---- body of while loop movea.l 16(a7), a0 * put base address of array in A0 * (prepare to access A[i]) move.l 4(a7), d0 * now d0 = i muls #4, d0 * offset is now in d0 move.l (a0, d0.w), d0 * put A[i] in d0 add.l d0, 0(a7) * add A[i] to local variable s move.l 4(a7), d0 add.l #1, d0 move.l d0, 4(a7) * i = i + 1 BRA While WhileEnd: move.l 0(a7), d0 * Return s in the agreed location (d0) * Note: the stack is STILL: * * Offsets * +---------------+ <----- a7 (stack pointer) * 0(a7) | s | (you decide which location is s and i) * +---------------+ * 4(a7) | i | (This program uses s and i in the given manner) * +---------------+ * 8(a7) | return address| * +---------------+ * 12(a7) | n (10) | * +---------------+ * 16(a7) | A (#A) | * +---------------+ * * If you return NOW, your program will NOT pop the return address * into the Program counter and it will CRASH !!! adda.l #8, a7 * Remove local variables !!! * NOW the stack is: * * Offsets * +---------------+ <----- a7 (stack pointer) * 8(a7) | return address| * +---------------+ * 12(a7) | n (10) | * +---------------+ * 16(a7) | A (#A) | * +---------------+ * * NOW you can rexecute the return instruction !!! rts |
main --------> func1 -----------> func2 -------------> func3 Stack: +------------+ | func3 local| +------------+ | ret. func2 | +------------+ | func3 param| +------------+ +------------+ | func2 local| | func2 local| +------------+ +------------+ | ret. func1 | | ret. func1 | +------------+ +------------+ | func2 param| | func2 param| +------------+ +------------+ +------------+ | func1 local| | func1 local| | func1 local| +------------+ +------------+ +------------+ | ret. main | | ret. main | | ret. main | +------------+ +------------+ +------------+ | func1 param| | func1 param| | func1 param| +------------+ +------------+ +------------+ |
Notice that:
|
|
Because:
|
Offsets used to access variables BEFORE adding extra local variable | Offsets used to access variables AFTER adding extra local variable |
---|---|
+---------------+ <----- a7 0(a7) | s | +---------------+ 4(a7) | i | +---------------+ 8(a7) | return address| +---------------+ 12(a7) | n (10) | +---------------+ 16(a7) | A (#A) | +---------------+ |
+---------------+ <----- a7 0(a7) | x | +---------------+ 4(a7) | s | +---------------+ 8(a7) | i | +---------------+ 12(a7) | return address| +---------------+ 16(a7) | n (10) | +---------------+ 20(a7) | A (#A) | +---------------+ All offsets has changed !!! |