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 |