1 / 46

Subroutines

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. Three main concepts involved:

emile
Télécharger la présentation

Subroutines

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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

  2. Subroutines • Three main concepts involved: • How to transfer control from calling program to a subroutine and back • How to pass parameter values to a subroutine and results back from the subroutine • How to write subroutine code that is independent of the calling program

  3. Subroutines • "open" subroutine = macro • resolved before assembly by textual substitution, • body of routine is placed in-line at call site with parameter substitution • (highly crafted macro example is cmul in appendix B of text) • "closed" subroutine = standard notion • branch/execute/return at run time • one copy of body which accesses its formal parameters

  4. Subroutines • Parameters: • actual parameters - values or addresses passed to subroutine • formal parameters - parameter names appearing in subroutine

  5. Subroutines 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 return addresses

  6. C functions main() {inta,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 this?

  7. C functions .text .global main .type main, %function main: push {lr} movr0, #37 @ put x in r0 movr1, #55 @ put y in r1 bl sum . . . movr0, #0 pop {pc} .global sum .type main, %function sum: push {lr} add r0, r0, r1 pop {pc}

  8. C functions x86 example output for swap routine in C (sp called esp, fp called ebp) void main() { main: void swap(); pushl %ebp ! save old bp inta,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 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

  9. C functions ARM code for swap() void swap(int *x, int *y) { swap: @ addr x is in r0 inttemp; @ addr y is in r1 temp = *x; push {lr} @ save return address *x = *y;ldrr2, [r0] @ move x into r2 *y = temp;ldrr3, [r1] @ move y into r3 return;strr3, [r0] @ store indirectly } @ into x str r2, [r1] @ store indirectly @ into y mov r0, #0 pop {pc}

  10. Subroutines – parameter passing • handling a return value is not illustrated in the previous examples • a subroutine passes a value back, typically through register r0; if more than one value, then through registers r0 – r3 • the caller copies the value

  11. Subroutines – parameter passing • passing data to/from a subroutine can be done through the parameters and through the return value of a function subroutine • parameter passing methods include: call-by-value - input parameters (declared with "IN") in Ada - default method for parameters in C, C++, and Pascal - parameters of primitive type in Java call-by-result - output parameters (declared with "OUT") in Ada

  12. Subroutines – parameter passing Parameter passing methods include: • call-by-value-result - in/out parameters (declared with "IN OUT") in Ada • call-by-reference - large array parameters in Ada - array parameters in C and C++ - reference parameters (declared with "&") in C++ - reference parameters (declared with "VAR") in Pascal - object parameters in Java - default method for parameters in Fortran

  13. Subroutines – parameter passing Parameter passing (cont’d) • call-by-value - copy values of actual parameters into memory locations of formal parameters before executing the body of the subroutine; do nothing on return main a = 1 a: 1 b = 2 b: 2 call subr(a,b) pass 1,2 via stack print a,b print 1,2 subr(x,y) copy 1,2 into x,y ^ x = x + 1 x: /1/ 2 | y = x + y y: /2/ 4 | return ---------------------'

  14. Subroutines – parameter passing Parameter passing (cont’d) • call-by-result - do nothing prior to executing the body of the subroutine; copy the final values of the formal parameters into the memory locations of the actual parameters on return main a = 1 a: 1 b = 2 b: 2 call subr(a,b) pass nothing receive ?,? from subr into a,b a: /1/ ? b: /2/ ? print a,b print ?,? subr(x,y) copy ?,? into x,y ^ x = x + 1 x: /?/ ? | y = x + y y: /?/ ? | return pass ?,? back via stack --------'

  15. Subroutines – parameter passing Parameter passing (cont’d) • call-by-value-result - perform copying of values both before and after executing the body of the subroutine main a = 1 a: 1 b = 2 b: 2 call subr(a,b) pass 1,2 via stack receive 2,4 from subr into a,b a: /1/ 2 b: /2/ 4 print a,b print 2,4 subr(x,y) copy 1,2 into x,y ^ x = x + 1 x: /1/ 2 | y = x + y y: /2/ 4 | return pass 2,4 back via stack --'

  16. Subroutines – parameter passing Parameter passing (cont’d) • call-by-reference • pass the addresses of the actual parameters • copy these addresses into the memory locations of the formal parameters • on each reference to a formal parameter in the body of the subroutine, perform an indirect reference to the corresponding actual parameter; • i.e. the formal parameter is an alias of the actual parameter, thus both the formal and actual parameter "name" refer to the same object • changes made using the formal parameter are being executed on the object passed as the actual parameter

  17. Subroutines – parameter passing Parameter passing (cont’d) • call-by-reference (cont’d) main a = 1 a: 1 a: /1/ 2 action in subr b = 2 b: 2 b: /2/ 4 action in subr call subr(a,b) pass &a,&b via stack print a,b print 2,4 subr(x,y) copy &a,&b into x,y ^ x = x + 1 x: &a thus a = a + 1 | y = x + y y: &b thus b = a + b | return ------------------------------------'

  18. Subroutines – parameter passing consider Fortran's call-by-reference applied to a constant parameter - what should the following code print? SUBROUTINE ADDONE( I ) I = I + 1 RETURN END ... ADDONE( 2 ) WRITE(6,10) 2 10 FORMAT('CONSTANT 2 =',I1)

  19. Subroutines – parameter passing (tradeoffs) optimizations can pass parameters in registers (not using stack) can sometimes not save/restore registers when executing a leaf routine

  20. Subroutines – parameter passing [language note: you may come across call-by-name; it is an obsolete and complex parameter passing mechanism proposed for Algol 60; John Levine writes in comp.compilers in April 2009: "Alan Perlis, who was on the Algol 60 committee, told me that call by name was a mistake. They were trying to make an elegant definition of call by reference, and didn't realize what they'd done until Jensen's Device came along."] [language note: Dr. MuraliSitaraman of Clemson advocates call-by-swapping since it avoids aliasing; see www.nvc.vt.edu/gregwk/tako/swapping.html]

  21. 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)

  22. Role of ARM Registers in Procedure Calls

  23. 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

  24. Register Usage Register Arguments into function Result(s) from function otherwise corruptible (Additional parameters passed on stack) r0 r1 r2 r3 r4 r5 r6 Register variables Must be preserved r7 r8 r9/sb - Stack base r10/sl - Stack limit if software stack checking selected r11 Scratch register (corruptible) r12 Stack PointerLink Register Program Counter r13/sp - SP should always be 8-byte (2 word) aligned r14/lr - R14 can be used as a temporary once value stacked r15/pc

  25. Instruction Support for Functions ... 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 MOV lr,1016 @ lr = 10161012 B sum @ branch to sum1016 ... 2000 sum: ADD r0,r0,r12004 BX lr @ MOV pc, lr i.e., return C A R M

  26. Instruction Support for Functions ... sum(a,b);... @a,b: r0,r1 }int sum(int x, int y) { return x+y;} C 2000 sum: ADD r0,r0,r12004 BX lr @ new instruction Question: Why use BX? Why not simply use B? Answer: sum might be called by many functions, so we can’t return to a fixed place. The calling routine to sum must be able to say“return here”somehow. A R M

  27. General structure of a subroutine main program call return

  28. Instruction Support for Functions BL subroutine_name(Branch-and-Link) is the instruction to jump to a subroutine. It performs the following operations: • BL functionality: • 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)

  29. 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

  30. Nested Procedures intsumSquare(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.

  31. 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

  32. 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: intsumSquare(int x, int y) { return mult(x, x) + y;}

  33. Using the Stack • intsumSquare(int x, int y) • { return mult(x, x)+ y; • } sumSquare: ADD sp,sp,#-8 @ space on stack STR lr, [sp,#4] @ save ret addr STR r1, [sp] @ save y "push" 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 addrADD sp,sp,#8 @restore stack BX lrmult: ... "pop"

  34. 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? • Save necessary values onto stack • Assign argument(s), if any • BL call • Restore values from stack

  35. 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.

  36. 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.

  37. 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.

  38. 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. • Function E must save any saved registers it intends to use before garbling up their values • Remember: Caller/callee need to save only volatile/saved registers they are using, not all registers.

  39. Basic Structure of a Function entry_label: ADD sp,sp,-framesizeSTR lr,[sp, #framesize-4] @save lrsave other regs if necessary ... restore other regs if necessaryLDR lr,[sp, framesize-4] @ restore lrADD sp,sp, #framesizeBX lr Prologue Body (call other functions…) Epilogue

  40. Example main() {intx, y; /* x: r0, y: r1 */...m = mult(y,y); ... } intmult (int multiplicand, int multiplier) {int product; product = 0; while (multiplier > 0) { product += multiplicand; multiplier -= 1; } return product; }

  41. Example .global main .type main, %function x .req r4 y .req r5 prod .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 */ movr0, x movr1, y blmult @ call mult movr3,r0 @ m = mult(x, y) done: … movr0, #0 pop {r4, r5, pc}

  42. 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}

  43. Passing Parameters to Subroutines in ARM Parameters can be passed to subroutines in three ways: • Through registers • Through memory • Via the stack

  44. Passing Parameters in registers • This is what we have done so far • Fast way of transferring data

  45. Passing Parameters by Reference • Parameters can easily be stored in program memory and then loaded as they are used • Send the subroutine 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

  46. 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.

More Related