230 likes | 268 Views
Embedded Systems Programming. Stacks and functions. Function calling. /* * a program to see how arm assembler implements function calls- craig * 12/10/04 */ int do_it(int, int, int, int); main() { int i,j; i = 10; j = 20; do_it(1,2,3,4); }
E N D
Embedded Systems Programming Stacks and functions
Function calling • /* • * a program to see how arm assembler implements function calls- craig * 12/10/04 • */ • int do_it(int, int, int, int); • main() • { • int i,j; • i = 10; • j = 20; • do_it(1,2,3,4); • } • int do_it(int a, int b, int c,int d) • { • int i,j; • i = 10; • j = a + b + c + d; • return -1; • } Function prototype Local variables Actual arguments parameters Return value
Passing parameters to functions • Passing variable length parameter lists to functions provides a number of problems for language implementers • There are a number of techniques for passing parameters to functions • Using pre-determined parameter blocks • Using registers • Using the stack
Pre-determined parameter blocks • All functions either know of, or are passed a parameter block where the parameters are placed • Very simple to implement • No problems with variable length parameter list • Recursion is not possible • How much space for the parameter block?
Using registers • Machine registers can be used • Register access is very fast • Easy to implement • Limited number of registers • Some processor have very few & they may be used for other purposes • Have to be saved for recursion • Block other uses of registers
Using the stack • A very popular way of passing parameters is by placing them at a know place on the run-time stack • Allows variable length parameter lists • Allows recursion • Can be slightly complex • Stack overflow?
Parameters on the stackM68k example Low memory Parameters Frame Pointer -8 Return address Old frame pointer Frame pointer Local Variables Save registers Stack Pointer High memory
Parameters with ARM C • ARM C uses a mixture of registers and the stack • This means that for small numbers of parameters it is very efficient……. • ……but it can have variable length lists • Allows for programmer optimisation • Restricting use of parameters passed to functions
The APCS • Procedure calls are defined in the ARM Procedure Call Standard (APCS) • There is a Thumb version ARM THUMB Procedure Call Standard (ATPCS) • These standards explain how parameters and return values are passed. They give details on how the stack should look on procedure entry and exit
APCS argument passing SP+ 16 Argument 8 SP+ 12 Argument 7 SP+ 8 Argument 6 SP+ 4 Argument 5 SP Argument 4 R3 Argument 3 R2 Argument 2 Argument 1 R1 Argument 0 Return value R0
Passing parameters • /* • * a program to see how arm assembler implements function calls- craig * 12/10/04 • */ • int do_it(int, int, int, int); • main() • { • int i,j; • i = 10; • j = 20; • do_it(1,2,3,4); • } • int do_it(int a, int b, int c,int d) • { • int i,j; • i = 10; • j = a + b + c + d; • return -1; • }
gcc2_compiled.:.text .align 2 .global main .type main,functionmain: @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #8mov r3, #10 str r3, [fp, #-16] mov r3, #20 str r3, [fp, #-20] mov r0, #1mov r1, #2 mov r2, #3 mov r3, #4 bl do_it.L2: ldmea fp, {fp, sp, pc}.Lfe1: .size main,.Lfe1-main .align 2 .global do_it .type do_it,function Variable i Variablej } Parameters
do_it: @ args = 0, pretend = 0, frame = 24 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #24 str r0, [fp, #-16] str r1, [fp, #-20] str r2, [fp, #-24]str r3, [fp, #-28] mov r3, #10 str r3, [fp, #-32] ldr r3, [fp, #-16] ldr r2, [fp, #-20] add r3, r3, r2 ldr r2, [fp, #-24] add r3, r3, r2 ldr r2, [fp, #-28] add r3, r3, r2 str r3, [fp, #-36] mvn r0, #0 b .L3.L3: ldmea fp, {fp, sp, pc}.Lfe2: .size do_it,.Lfe2-do_it .ident "GCC: (GNU) 2.95.3 20010315 (release)" } Saving parameters Variable i Variable j Return value -1
/* * A program to see how arm assembler implements long * Parameter lists - craig 12/10/04 */ void do_it(int, int, int, int, int, int); main() { int i,j; i = 10; j = 20; do_it(1,2,3,4,5,6); } void do_it(int a, int b, int c,int d, int e, int f) { int i,j; i = 10; j = a + b + c + d + e + f; }
.text .align 2 .global main .type main,functionmain: @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #16mov r3, #10 str r3, [fp, #-16] mov r3, #20 str r3, [fp, #-20] mov r3, #5 str r3, [sp, #0] mov r3, #6 str r3, [sp, #4] mov r0, #1mov r1, #2 mov r2, #3 mov r3, #4 bl do_it.L2: ldmea fp, {fp, sp, pc}.Lfe1: .size main,.Lfe1-main Parameter 5 Parameter 6
.align 2 .global do_it .type do_it,functiondo_it: @ args = 8, pretend = 0, frame = 24 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #24 str r0, [fp, #-16] str r1, [fp, #-20] str r2, [fp, #-24]str r3, [fp, #-28] mov r3, #10 str r3, [fp, #-32] ldr r3, [fp, #-16] ldr r2, [fp, #-20] add r3, r3, r2 ldr r2, [fp, #-24] add r3, r3, r2 ldr r2, [fp, #-28] add r3, r3, r2 ldr r2, [fp, #4] add r3, r3, r2 ldr r2, [fp, #8] add r3, r3, r2 str r3, [fp, #-36].L3: ldmea fp, {fp, sp, pc}.Lfe2: .size do_it,.Lfe2-do_it Register r3 reused } Parameters 5 and 6
Compiler Optimisation • The compiler can requested to optimise code • This is the –On switch where n is a number between 1 (lowest) and 3 (highest) • Embedded programmers will need to do extra, pre-assembly, optimisation
a program to see how arm assembler implement • * parameter passing - craig 12/10/04 • */ • int do_it(int, int, int, int, int, int); • main() • { • int i,j; • i = 10; • j = 20; • do_it(1,2,3,4,5,6); • } • int do_it(int a, int b, int c,int d, int e, int f) • { • int i,j; • i = 10; • j = a + b + c + d + e + f; • return j ; • }
.text .align 2 .global do_it .type do_it,functiondo_it: @ args = 8, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 add r1, r0, r1 add r1, r1, r2 ldr r2, [fp, #4] add r1, r1, r3 ldr r0, [fp, #8] add r1, r1, r2 add r0, r1, r0 ldmea fp, {fp, sp, pc}.Lfe1: .size do_it,.Lfe1-do_it
.align 2 .global main .type main,functionmain: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} mov r3, #5 sub sp, sp, #8 str r3, [sp, #0] sub fp, ip, #4mov r2, #6 str r2, [sp, #4] mov r0, #1mov r1, #2 sub r2, r2, #3 sub r3, r3, #1 bl do_it ldmea fp, {fp, sp, pc}.Lfe2: .size main,.Lfe2-main
Passing parameters • /* • * a program to see how arm assembler implements function calls- craig * 12/10/04 • */ • int do_it(int, int, int, int); • main() • { • int i,j; • i = 10; • j = 20; • do_it(1,2,3,4); • } • int do_it(int a, int b, int c,int d) • { • int i,j; • i = 10; • j = a + b + c + d; • return -1; • }
gcc2_compiled.:.text .align 2 .global do_it .type do_it,functiondo_it: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 mvn r0, #0 ldmea fp, {fp, sp, pc}.Lfe1: .size do_it,.Lfe1-do_it .align 2 .global main .type main,functionmain: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 mov r0, #1 mov r1, #2 mov r2, #3 mov r3, #4 bl do_it ldmea fp, {fp, sp, pc}.Lfe2: .size main,.Lfe2-main .ident "GCC: (GNU) 2.95.3 20010315 (release)"