Embedded Systems Programming Stacks and functions Passing parameters

Embedded Systems Programming Stacks and functions

Passing parameters to functions • Passing variable length parameter lists to functions provides a number of problems for language implementers • There 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 stack M 68 k example Parameters Return address Frame pointer Old frame pointer Local Variables Stack Pointer Save registers Frame Pointer -8

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 register usage Register No. Alternate name APCS R 0 A 1 Return value & argument R 1 A 2 register. Used for first 4 R 2 A 3 Function parameters. Used R 3 A 4 scratch registers R 4 V 1 General variable registers R 5 V 2 Saved and restored on R 6 V 3 function entry R 7 V 4 R 8 V 5 R 9 V 6/SB Base addr of RW data R 10 V 7/SL Stack checking limit R 11 V 8/FP Frame pointer R 12 IP Intraprocedure call register R 13 SP Stack pointer R 14 LR Link register return address R 15 PC Program counter

APCS argument passing SP+ 16 SP+ 12 Argument 8 Argument 7 SP+ 8 SP+ 4 Argument 6 Argument 5 SP Argument 4 R 3 Argument 3 R 2 Argument 2 R 1 Argument 1 R 0 Argument 0 Return value

Passing parameters • /* • * a program to see how arm assembler implements function calls- craig * 12/10/04 • */ • int do_it(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; • }

gcc 2_compiled. : . text. align 2. global main. type main, function main: @ 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, #8 Variable i mov r 3, #10 str r 3, [fp, #-16] Variablej mov r 3, #20 str r 3, [fp, #-20] mov r 0, #1 mov r 1, #2 Parameters mov r 2, #3 mov r 3, #4 bl do_it. L 2: ldmea fp, {fp, sp, pc}. Lfe 1: . size main, . Lfe 1 -main. align 2. global do_it. type do_it, function }

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, #24 str r 0, [fp, #-16] str r 1, [fp, #-20] str r 2, [fp, #-24] Saving parameters str r 3, [fp, #-28] mov r 3, #10 Variable i str r 3, [fp, #-32] ldr r 3, [fp, #-16] ldr r 2, [fp, #-20] add r 3, r 2 ldr r 2, [fp, #-24] add r 3, r 2 ldr r 2, [fp, #-28] add r 3, r 2 str r 3, [fp, #-36] Variable j mvn r 0, #0 b. L 3 } . L 3: Return value -1 ldmea fp, {fp, sp, pc} . size. ident do_it, . Lfe 2 -do_it "GCC: (GNU) 2. 95. 3 20010315 (release)" . Lfe 2:

/* * A program to see how arm assembler implements long * Parameter lists - craig 12/10/04 */ void do_it(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. global. type 2 main, function main: @ 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, #16 mov r 3, #10 str r 3, [fp, #-16] mov r 3, #20 str r 3, [fp, #-20] mov r 3, #5 Parameter 5 str r 3, [sp, #0] mov r 3, #6 str r 3, [sp, #4] Parameter 6 mov r 0, #1 mov r 1, #2 mov r 2, #3 mov r 3, #4 bl do_it. L 2: ldmea fp, {fp, sp, pc} . size main, . Lfe 1 -main . Lfe 1:

. align 2. global. type do_it, function do_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, #24 str r 0, [fp, #-16] str r 1, [fp, #-20] str r 2, [fp, #-24] str r 3, [fp, #-28] mov r 3, #10 str r 3, [fp, #-32] ldr r 3, [fp, #-16] ldr r 2, [fp, #-20] add r 3, r 2 ldr r 2, [fp, #-24] add r 3, r 2 ldr r 2, [fp, #-28] add r 3, r 2 ldr r 2, [fp, #4] add r 3, r 2 ldr r 2, [fp, #8] add r 3, r 2 str r 3, [fp, #-36]. L 3: ldmea fp, {fp, sp, pc} . size do_it, . Lfe 2 -do_it . Lfe 2:

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-compilation, optimisation

• a program to see how arm assembler implement • * parameter passing - craig 12/10/04 */ int do_it(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. global. type 2 do_it, function do_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 r 1, r 0, r 1 add r 1, r 2 ldr r 2, [fp, #4] add r 1, r 3 ldr r 0, [fp, #8] add r 1, r 2 add r 0, r 1, r 0 ldmea fp, {fp, sp, pc}. Lfe 1: . size do_it, . Lfe 1 -do_it

. align 2. global. type main, function main: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} mov r 3, #5 sub sp, #8 str r 3, [sp, #0] sub fp, ip, #4 mov r 2, #6 str r 2, [sp, #4] mov r 0, #1 mov r 1, #2 sub r 2, #3 sub r 3, #1 bl do_it ldmea fp, {fp, sp, pc}. Lfe 2: . size main, . Lfe 2 -main

gcc 2_compiled. : . text. align 2. global do_it. type do_it, function do_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 r 0, #0 ldmea fp, {fp, sp, pc}. Lfe 1: . size do_it, . Lfe 1 -do_it. align 2. global main. type main, function main: @ 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 r 0, #1 mov r 1, #2 mov r 2, #3 mov r 3, #4 bl do_it ldmea fp, {fp, sp, pc}. Lfe 2: . size main, . Lfe 2 -main
- Slides: 21