main()
{
int a, b, c;
c = sum(a, b);
}
|
int sum(int x, int y)
{
x = x + 1;
y = y + 1;
return (x*x + y*y);
}
|
main()
{
c = func_1(a, b);
}
|
int func_1(int x, int y)
{
int k, l, m;
....
m = func_2(k, l);
}
|
int func_2(int x, int y)
{
...
}
|
main ---------> func1 -----------> func2 ----------> func3 Stack: +------------+ | ret. func2 | +------------+ +------------+ | ret. func1 | | ret. func1 | +------------+ +------------+ +------------+ | ret. main | | ret. main | | ret. main | +------------+ +------------+ +------------+ |
main ------------> func1 --------------> func2 -------------> func3 push func1 param push func2 param push fucn3 param bsr func1 bsr func2 bsr func3 Stack: +------------+ | ret. func2 | +------------+ | func3 param| +------------+ +------------+ | ret. func1 | | ret. func1 | +------------+ +------------+ | func2 param| | func2 param| +------------+ +------------+ +------------+ | ret. main | | ret. main | | ret. main | +------------+ +------------+ +------------+ | func1 param| | func1 param| | func1 param| +------------+ +------------+ +------------+ |
+-------------+
4004 | |
+-------------+
4008 | |
+-------------+ <---- a7 = 4012
4012 | aaaaaaaa |
+-------------+
4016 | bbbbbbbb |
+-------------+
| ........ | (each rectangle represents 4 bytes)
|
+-------------+
4004 | |
+-------------+ <---- a7 = 4008
4008 | 6789 |
+-------------+
4012 | aaaaaaaa |
+-------------+
4016 | bbbbbbbb |
+-------------+
| ........ | (each rectangle represents 4 bytes)
|
suba.l #4, a7
move.l #6789, (a7)
|
move.l <ea>, -(a7) is same as: suba.l #4, a7
move.l <ea>, (a7)
move.w <ea>, -(a7) is same as: suba.l #2, a7
move.w <ea>, (a7)
|
main: int a, b, c; c = sum(a, b); |
int sum(int x, int y)
{
x = x + 1;
y = y + 1;
return ( x*x + y*y );
}
|
main:
move.l a, -(a7) * Pass a on stack
move.l b, -(a7) * Pass b on stack
bsr sum * Call subroutine sum
adda.l #8, a7 * remove a and b from stack
move.l d0, c * put return value in c
|
+---------------+
| free space |
+---------------+ <----- a7 (stack pointer)
0(a7) | return address|
+---------------+
4(a7) | b | parameter y (has the value b)
+---------------+
8(a7) | a | parameter x (has the value a)
+---------------+
| ..... |
|
The subroutine returns the value in register D0.
sum:
move.l 8(a7), d0 * puts first parameter x in d0
add.l #1, d0
move.l d0, 8(a7) * puts x+1 back into the param var x
move.l 4(a7), d0 * puts 2nd parameter y in d0
add.l #1, d0
move.l d0, 4(a7) * puts y+1 back into the param var y
move.l 8(a7), d0 * puts first parameter x in d0
muls d0, d0 * now d0 = x*x
move.l 4(a7), d1 * puts second parameter y in d1
muls d1, d1 * now d1 = y*y
add.l d1, d0 * now d0 = x*x + y*y, in agreed return location
rts
|
NOTE:
That's why we need:
main:
move.l a, -(a7)
move.l b, -(a7)
bsr sum
adda.l #8, a7 * remove (pop) a and b from stack
move.l d0, c * put return value in variable c
|
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 !!!
|
| We use a fixed pointer that points to a relatively fixed location in the stack and use this fixed pointer to access the parameters and local variables |
Answer: at the separation point between the parameters and local variables
+---------------+ <----- a7 (stack pointer)
-8(a6) | s | Local variable
+---------------+
-4(a6) | i | Local variable
+---------------+ <----- a6 (frame pointer)
0(a6) | return address|
+---------------+
4(a6) | n (10) | Parameter
+---------------+
8(a6) | A (#A) | Parameter
+---------------+
|
| Offsets used to access variables BEFORE adding extra local variable | Offsets used to access variables AFTER adding extra local variable |
|---|---|
+---------------+ <----- a7
-8(a6) | s |
+---------------+
-4(a6) | i |
+---------------+ <----- a6
0(a6) | return address|
+---------------+
4(a6) | n (10) |
+---------------+
8(a6) | A (#A) |
+---------------+
|
+---------------+ <----- a7
-12(a6) | x |
+---------------+
-8(a6) | s |
+---------------+
-4(a6) | i |
+---------------+ <----- a6
0(a6) | return address|
+---------------+
4(a6) | n (10) |
+---------------+
8(a6) | A (#A) |
+---------------+
|
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.
*********************************************************
* This version does NOT save A6 - we will fix it later *
*********************************************************
ArraySum:
movea.l a7, a6 * setup a6 !!!
* The stack is:
*
* Offsets
* +---------------+ <----- a6 and a7 (stack pointer)
* 0(a6) | return address|
* +---------------+
* 4(a6) | n (10) |
* +---------------+
* 8(a6) | A (#A) |
* +---------------+
suba.l #8, a7 * Create 2 local variables on stack !!!
* NOW the stack is:
*
* Offsets
* +---------------+ <----- a7 (stack pointer)
* -8(a6) | s | (you decide which location is s and i)
* +---------------+ (This program uses s and i in the given manner)
* -4(a6) | i |
* +---------------+ <----- a6 (frame pointer)
* 0(a6) | return address|
* +---------------+
* 4(a6) | n (10) |
* +---------------+
* 8(a6) | A (#A) |
* +---------------+
move.l #0, -8(a6) * s = 0
move.l #0, -4(a6) * i = 0
While:
move.l -4(a6), d0 * puts local variable i in d0
move.l 4(a6), d1 * puts parameter n in d1
cmp.l d1, d0
BGE WhileEnd * Exit while loop if i >= n
* ---- body of while loop
movea.l 8(a6), a0 * put base address of array in A0
* (prepare to access A[i])
move.l -4(a6), 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, -8(a6) * add A[i] to local variable s
move.l -4(a6), d0
add.l #1, d0
move.l d0, -4(a6) * i = i + 1
BRA While
WhileEnd:
move.l -8(a6), d0 * Return s in the agreed location (d0)
* The stack is STILL:
*
* Offsets
* +---------------+ <----- a7 (stack pointer)
* -8(a6) | s |
* +---------------+
* -4(a6) | i |
* +---------------+ <----- a6 (frame pointer)
* 0(a6) | return address|
* +---------------+
* 4(a6) | n (10) |
* +---------------+
* 8(a6) | A (#A) |
* +---------------+
*
* If you return NOW, your program will NOT pop the return address
* into the Program counter and it will CRASH !!!
movea.l a6, a7 * NEW (better) way to remove local variables !!!
* Better you don't need to know how many local
* variables to remove !!!
* NOW the stack is:
*
* +---------------+ <----- a7 (stack pointer)
* | return address|
* +---------------+
* | n (10) |
* +---------------+
* | A (#A) |
* +---------------+
*
* NOW you can rexecute the return instruction !!!
rts
|
Therefore:
|
|
The subroutine returns the value in register D0.
ArraySum:
movea.l a6, -(a7) ********** Save a6 from the caller subroutine !!!!!!!!!
* The stack is now:
*
* +---------------+ <----- a7 (stack pointer)
* | a6 from caller|
* +---------------+
* | return address|
* +---------------+
* | n (10) |
* +---------------+
* | A (#A) |
* +---------------+
movea.l a7, a6 * (setup a6 to access local vars and parameters)
* The parameters can now be accessed through a6 as follows:
*
* Offsets
* +---------------+ <----- a6 and a7 (stack pointer)
* 0(a6) | a6 from caller|
* +---------------+
* 4(a6) | return address|
* +---------------+
* 8(a7) | n (10) |
* +---------------+
* 12(a7) | A (#A) |
* +---------------+
suba.l #8, a7 * Create 2 local variables on stack !!!
* NOW the stack is (along with offsets on how to access local variables):
*
* Offsets
* +---------------+ <----- a7 (stack pointer)
* -8(a6) | s | (you decide which location is s and i)
* +---------------+ (This program uses s and i in the given manner)
* -4(a6) | i |
* +---------------+ <----- a6 (frame pointer)
* 0(a6) | a6 from caller|
* +---------------+
* 4(a6) | return address|
* +---------------+
* 8(a6) | n (10) |
* +---------------+
* 12(a6) | A (#A) |
* +---------------+
move.l #0, -8(a6) * s = 0
move.l #0, -4(a6) * i = 0
While:
move.l -4(a6), d0 * puts local variable i in d0
move.l 8(a6), d1 * puts parameter n in d1
cmp.l d1, d0
BGE WhileEnd * Exit while loop if i >= n
* ---- body of while loop
movea.l 12(a6), a0 * put base address of array in A0
* (prepare to access A[i])
move.l -4(a6), 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, -8(a6) * add A[i] to local variable s
move.l -4(a6), d0
add.l #1, d0
move.l d0, -4(a6) * i = i + 1
BRA While
WhileEnd:
move.l -8(a6), d0 * Return s in the agreed location (d0)
* The stack is STILL:
*
* Offsets
* +---------------+ <----- a7 (stack pointer)
* -8(a6) | s |
* +---------------+
* -4(a6) | i |
* +---------------+ <----- a6 (frame pointer)
* 0(a6) | a6 from caller|
* +---------------+
* 4(a6) | return address|
* +---------------+
* 8(a6) | n (10) |
* +---------------+
* 12(a6) | A (#A) |
* +---------------+
*
* If you return NOW, your program will NOT pop the return address
* into the Program counter and it will CRASH !!!
movea.l a6, a7 * Remove the local variables.
* NOW the stack is:
*
* +---------------+ <----- a7 (stack pointer)
* | a6 from caller|
* +---------------+
* | return address|
* +---------------+
* | n (10) |
* +---------------+
* | A (#A) |
* +---------------+
*
* NOW is the time to recover the a6 value for the caller subroutine !!!
movea.l (a7)+, a6 ***************** restore a6 !!!!!!!!!!!!
* (The (a7)+ address mode is explained below)
* NOW the stack is:
*
* +---------------+ <----- a7 (stack pointer)
* | return address|
* +---------------+
* | n (10) |
* +---------------+
* | A (#A) |
* +---------------+
*
* NOW you can rexecute the return instruction !!!
rts
|
move.l (a7)+, <ea> is same as: move.l (a7), <ea>
adda.l #4, a7
move.w (a7)+, <ea> is same as: move.w (a7), <ea>
adda.l #2, a7
|