35
Subroutines reasons for subroutines repeat same code, or similar code with slightly different parameters hide design decisions or design complexity partition off code likely to change provide for separate compilation provide for reuse

Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Embed Size (px)

Citation preview

Page 1: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

reasons for subroutines− repeat same code, or similar code with slightly

different parameters− hide design decisions or design complexity− partition off code likely to change− provide for separate compilation− provide for reuse

Page 2: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

"open" subroutine = macro− resolved before assembly by textual

substitution,− body of routine is placed in-line at call site with

parameter substitution

"closed" subroutine = standard notion− branch/execute/return at run time− one copy of body which accesses its formal

parameters

Page 3: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

Three main concepts involved:

• Transferring control from calling program to a subroutine and back

• Passing parameter values to a subroutine and results back from the subroutine

• Writing subroutine code that is independent of the calling program

In addition, sometimes a subroutine must allocate space for local variables.

Page 4: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

Transferring control from calling program to a subroutine and back• Necessary to save the return address, then

branch to the subroutine.• This can be accomplished in ARM using the

branch and link instruction blbl subr_name

• To transfer control back to the calling program, can use the branch and exchange instruction bx

bx lr

Alternatively, you can pop the lr register to the pc

Page 5: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

• Placing a return address in a link register works as long as there are no nested subroutines.

• For nested subroutines, it is necessary to save the return address to the stack

• subroutine calls and returns are LIFO, and older processors typically save the return address of a caller by pushing it onto a memory stack

• older processors typically pass parameters by pushing them onto the same memory stack that holds the return addresses

Page 6: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Subroutines

Parameters:− actual parameters - values or addresses

passed to subroutine− formal parameters - parameter names

appearing in subroutine

Page 7: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

General structure of a subroutine

bl subr @ call subroutine

ret_addr: add r0, r1, r2

subr: … @ body of the subroutine

bx lr

@ return to caller

@ call @ return

main:

Page 8: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

C functions

main() {

int a,b,c; ...

c = sum(a,b); @ a,b,c:r0,r1,r2}

/* really dumb sum function */int sum(int x, int y) {

return x+y;}

What information mustcompiler/programmer keep track of?

What instructions can accomplish the return?

Page 9: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Function Call Bookkeeping

• Registers play a major role in keeping track of information for function calls• Register conventions:

–Return address lr–Arguments r0, r1, r2, r3–Return value r0, r1, r2, r3–Local variables r4, r5, … , r12

• The stack is also used (more on this later)

Page 10: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Register Usage

r8r9/sbr10/slr11

r12

r13/spr14/lrr15/pc

r0r1r2r3

r4r5r6r7

Register variablesMust be preserved

Arguments into functionResult(s) from functionotherwise corruptible(Additional parameters passed on stack)

Scratch register

(corruptible)Stack PointerLink Register

Program Counter

Register

- Stack base- Stack limit if software stack checking selected

- R14 can be used as a temporary once value stacked- SP should always be 8-byte (2 word) aligned

Page 11: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Register Usage

• The compiler has a set of rules known as a Procedure Call Standard that determines how to pass parameters to a function (see AAPCS)

• CPSR flags may be corrupted by function call. Assembler code which links with compiled code must follow the AAPCS at external interfaces

• The AAPCS is part of the new Application Binary Interface (ABI) for the ARM Architecture

Page 12: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Register Conventions

• CalleR: the calling function

• CalleE: the function being called

• When callee returns from executing, the caller needs to know which registers may have changed and which are guaranteed to be unchanged.

• Register Conventions: A set of generally accepted rules as to which registers will be unchanged after a procedure call (BL) and which may be changed.

Page 13: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Register Conventions

What do these conventions mean?– If function R calls function E, then function R

must save any temporary registers that it may be using onto the stack before making a BL call (caller saved register values).

– Function E must save any saved registers it intends to use before garbling up their values (callee saved register values)

– Remember: caller/callee need to save only volatile/saved registers they are using, not all registers.

Page 14: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Saved Register Conventions• r4-r11 (v1-v8): Restore if you change. Very

important. If the callee changes these in any way, it must restore the original values before returning.

• sp: Restore if you change. The stack pointer must point to the same place before and after the BL call, or else the caller will not be able to restore values from the stack.

Page 15: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Volatile Register Conventions

• lr: Can Change. The BX call itself will change this register. Caller needs to save on stack if nested call.

• r0-r3 (a1-a4): Can change. These are volatile argument registers. Caller needs to save if they’ll need them after the call. e.g., r0 will change if there is a return value

• r12 (ip) may be used by a linker as a scratch register between a routine and any subroutine it calls. It can also be used within a routine to hold intermediate values between subroutine calls.

Page 16: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Rules for Subroutines

• Called with a BL instruction, returns with a

BX lr (or MOV pc, lr)• Accepts up to 4 arguments in r0, r1, r2 and r3• Return value is always in r0 (and if necessary in r1, r2, r3)• Must follow register conventions (even in functions that

only you will call)!

What are the register conventions?1) Save necessary values onto stack2) Assign argument(s), if any3) BL call4) Restore values from stack

Page 17: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Instruction Support for Functions

BL subroutine_name (Branch-and-Link) is the instruction to jump to a subroutine. It performs the following operations:

– Step 1 (link): Save address of next instruction into lr (Why next instruction? Why not current one?)

– Step 2 (branch): Branch to the given label (subroutine name)

• BL always uses r14 to store the return address. r14 is called the link register (lr)

Page 18: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Instruction Support for Functions

BX - performs a branch by copying the contents of a general register, Rn, into the program counter, PC. The branch causes a pipeline flush and refill from the address specified by Rn.

• Instead of providing a label to jump to, the BX instruction provides a register which contains an address to jump to• Only useful if we know the exact address to jump• Very useful for function calls:

– BL stores return address in register (lr)– BX lr jumps back to that address

• Syntax for BX (branch and exchange):BX register

Page 19: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Instruction Support for Functionsmain(){ ... sum(a,b); // a,b:r4,r5 ... }

int sum(int x, int y) { return x + y;}

address1000 mov r0, r4 @ x = a1004 mov r1, r5 @ y = b 1008 bl sum @ lr = 1012 branch to sum1012 ...

2000 sum: ADD r0, r0, r12004 BX lr @ MOV pc, lr i.e., return

Note: returns to address 1012

C

ARM

Page 20: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

C functions

.text .global main .type main, %functionmain: push {lr} mov r0, #37 @ put x in r0 mov r1, #55 @ put y in r1 bl sum . . . mov r0, #0 pop {pc}

.global sum .type main, %function

sum: push {lr} add r0, r0, r1

pop {pc}

Page 21: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Nested Proceduresint sumSquare(int x, int y) {

return mult(x,x)+ y;}

• Some subroutine called sumSquare, and now sumSquare is calling mult.• There’s a value in lr that sumSquare wants to

jump back to, but this will be overwritten by the call to mult.• Need to save sumSquare’s return address before

the call to mult.

Page 22: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Nested Procedures• In general, it may be necessary to save some

other info in addition to lr.• When a C program is run, there are 3 important

memory areas allocated:– Static: Variables declared once per program,

cease to exist only after execution completes. e.g., C globals

– Heap: Variables declared dynamically

– Stack: Space to be used by subroutines during execution; this is where we can save register values

Page 23: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Using the Stack

• We have a register sp which always points to the last used space in the stack.• To use the stack, we decrement this pointer by

the amount of space we need and then fill it with info.• Consider the following C function:

int sumSquare(int x, int y) {

return mult(x, x) + y;}

Page 24: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Using the Stack

sumSquare: add sp,sp,#-8 @ space on stack str lr, [sp,#4] @ save ret addr str r1, [sp] @ save y

mov r1, r0 @ mult(x,x) bl mult @ call mult

ldr r1, [sp] @ restore y add r0,r0,r1 @ mult()+y ldr lr, [sp, #4] @ get ret addr add sp,sp,#8 @ restore stack bx lr

mult: ...

int sumSquare(int x, int y) {

return mult(x, x)+ y; }

"push"

"pop"

Page 25: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

C functions

x86 example of swap routine in C

void main() { main: void swap(); pushl %ebp ! save old bp int a,b; movl %esp,%ebp ! set new bp as

! current sp a = 5; b = 44; subl $8,%esp ! sub for a and b

swap(&a,&b); movl $5,-4(%ebp) ! initialize a } movl $44,-8(%ebp) ! initialize b leal -8(%ebp),%eax ! form addr of b pushl %eax ! push onto stack leal -4(%ebp),%eax ! form addr of a pushl %eax ! push onto stack call swap ! call addl $8,%esp ! clean parms off

! stack leave ret

Page 26: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

C functionsx86 example output for swap routine in C (sp called esp, fp called ebp)

void swap(x,y) swap: int *x,*y; pushl %ebp ! save old bp { movl %esp,%ebp ! set new bp as current sp int temp; subl $4,%esp ! sub for temp temp = *x; movl 8(%ebp),%eax ! move addr x into eax *x = *y; movl (%eax),%edx ! indirectly get value in a *y = temp; movl %edx,-4(%ebp) ! store into temp return; movl 8(%ebp),%eax ! move addr x into eax } movl 12(%ebp),%edx ! move addr y into edx movl (%edx),%ecx ! indirectly get value in b movl %ecx,(%eax) ! store indirectly into a movl 12(%ebp),%eax ! move addr y into eax movl -4(%ebp),%edx ! move temp into edx movl %edx,(%eax) ! store indirectly into b leave ret

Page 27: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

C functions

ARM code for swap()

void swap(int *x, int *y){ swap: @ addr x is in r0 int temp; @ addr y is in r1 temp = *x; push {lr} @ save return address *x = *y; ldr r2, [r0] @ move x into r2 *y = temp; ldr r3, [r1] @ move y into r3 return; str r3, [r0] @ store indirectly into x} str r2, [r1] @ store into y mov r0, #0 pop {pc}

Page 28: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Basic Structure of a Function

entry_label: add sp,sp, -framesize str lr, [sp, #framesize-4] @ save lr @ save other regs if necessary

...

restore other regs if necessary ldr lr, [sp, framesize-4] @ restore lr add sp,sp, #framesize bx lr

Epilogue

Prologue

Body (call other functions…)

Page 29: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Examplemain() {

int x, y; /* x: r0, y: r1 */ ... m = mult(y,y);

... }int mult (int multiplicand, int multiplier){

int product; product = 0;

while (multiplier > 0) {

product += multiplicand; multiplier -= 1;

} return product;

}

Page 30: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Example .global main .type main, %function

x .req r4y .req r5prod .req r3

main: push {r4, r5, lr} @ save registers mov x, #7 @ put x in r4 mov y, #5 @ put y in r5

/* set up registers for call to mult */ mov r0, x mov r1, y bl mult @ call mult mov r3,r0 @ m = mult(x, y)

done: … mov r0, #0 pop {r4, r5, pc}

Page 31: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Example .global mult .type mult, %function

mult: push {lr} product .req r2 multiplicand .req r0 multiplier .req r1

mov product, #0 cmp multiplier, #0 ble finished

loop: add product, product, multiplicand sub multiplier, multiplier, #1 cmp multiplier, #0 bgt loop

finished: mov r0, product pop {pc}

Page 32: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Passing Parameters to Subroutines in ARM

Parameters can be passed to subroutines in three ways:• Through registers• Through memory• Via the stack

Page 33: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Passing Parameters in registers

• This is what we have done so far• Fast way of transferring data

Page 34: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Passing Parameters by Reference• Parameters can easily be stored in program

memory and then loaded as they are used• Send the address of the data to the subroutine• More efficient in terms of register usage for

some types of data, e.g. a long string of characters or an array of int values

Page 35: Subroutines reasons for subroutines −repeat same code, or similar code with slightly different parameters −hide design decisions or design complexity −partition

Passing Parameters on the stack

• Similar to passing parameters in memory• The subroutine uses a dedicated register for a

pointer into memory – the stack pointer, register r13.

• Data is pushed onto the stack before the subroutine call

• The subroutine gets the data off the stack.• The results are then stored back onto the stack

to be retrieved by the calling routine.