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 !!!
|