220 likes | 365 Views
Function Calling. Mips Assembly Call and Return. Steps for procedure calling Save the return address Jump to the procedure (function) Execute the procedure Return from the procedure MAL (mips assembly language) has one statement for the first 2 steps JAL : jump and link. JAL.
E N D
Mips Assembly Call and Return • Steps for procedure calling • Save the return address • Jump to the procedure (function) • Execute the procedure • Return from the procedure • MAL (mips assembly language) has one statement for the first 2 steps • JAL : jump and link
JAL • The jump and link • Places the return address (the contents of the PC) into register $31 • The PC is incremented during the fetch part of the instruction cycle • This is done during the execute phase, so the PC has the address of the instruction after the JAL instruction • Then jumps to the statement with the label used in the JAL statement
JAL usage • JAL procedure_name • JAL sqrt • Saves the address of the statement after the JAL in $31 and jumps to the statement with the label sqrt. • Register $31 can also be referred to as $ra (return address). • Register $31 is implied (not explicit) in the JAL instruction.
Return • Now register $31 has the return address. • Need to jump to the instruction whose address is in $31. • jr $31 • Jump register • Jumps to the address in the register specified.
Nested Calls • This process of calling and returning using register $31 works fine for a single call and return. • However if the procedure calls a procedure, the first return address is lost when the second JAL is done. • Need to save the value of $31 at the beginning of the function so it does not get clobbered inside the function.
Returning Order • We return to the most recently made JAL that has not been returned to. • This is the process of a stack (LIFO). • Use a stack to keep the “return addresses” • The system has a stack that we can use for this process.
System Stack • The system stack is in main memory starting at the “end” of memory. • The program starts at the “beginning” of memory • This stack grows “backwards”. • Recall, that when implementing a stack with an array, we need a “top” pointer. • The “top” pointer is register $29 • Also called $sp
Using the System Stack • The system stack pointer starts at the “end” of memory. • It grows “up” not “down”. • When you do a push, you need to subtract from the “top” ($sp) • When you do a pop, you need to add to the “top” ($sp)
Pushing and Popping • To push register $31 onto the stack, use sw $31,0($sp) add $sp, $sp, -4 • To pop a value off the stack and put it into register $31, use add $sp, $sp, 4 lw $31, 0($sp)
Stacking Return Addresses • The “best” convention to use is to ALWAYS start the procedure with the code to push the return address onto the stack • Do this even if your procedure does not call another procedure. You may add a JAL into the procedure later. • ALWAYS pop the return address from the stack before doing the return (JR).
Activation Records • We have been using local variables in procedures. They are very useful. • Our “variables” are registers. • The calling procedure wants the values in registers to be the same after the called procedure returns as they were before the procedure was called.
Local Values • We can push the values of the registers onto the stack and then pop them off just before we do the return. • We need to consider if we want to push all registers or just the registers the procedure uses. • Need to be careful if we make changes to the procedure and start to use a register we have not saved
Communication • We also need a technique to “send” values to the procedure (arguments – parameters) • We also need a way to send values back to the calling procedure (return values and/or reference arguments) • We can have any number of arguments • Use registers $a0-$a3 for the first 4 args. • Use the stack for passing additional arguments
Passing Additional Arguments • Push the arguments onto the stack before calling the procedure. Here is an example of passing 3 arguments (by value) sw $5, 0($sp) sw $8, -4($sp) sw $15, -8($sp) add $sp, $sp, -12 jal myproc
Using Parameters • Now to get those arguments, we can have lw $11,4($sp) lw $14, 8($sp) lw $18, 12($sp) • Note that these offsets are off by 4 from the stores because we would have pushed the return address at the beginning of the procedure and subtracted 4 from $sp
Returning a value • Most languages only allow one return value. • Since this is what we have used in the past, we will adhere to this convention. • This way, we can return the value in a register • Therefore, a register must be “set aside” for return values. • It must not be “restored” before returning from a function
Types of Parameters • We know about pass by value and pass by reference. • Pass by reference what you get in C++ when you use & in the parameter list. • The examples we used were pass by value. We passed a value in the stack and neither the register or the memory location values were changed.
Pass by Reference • Pass by reference passes the address of the variable. • To accomplish this in MAL, we would pass the address of the variable by placing it in the stack.
Reference Passing Example la $5,arg1 sw $5,0($sp) add $sp, $sp, -4 jal myproc ⋮ myproc: sw $31, 0($sp) add $sp, $sp, -4 lw $8, 4($sp) lw $6, 0($8) #now have the value of arg1 ⋮ sw $9, 0($8) #stored result from $9 into arg1 add $sp, $sp, 8 #go past return and parameter lw $31, -4($sp) jr $31
Register Usage Conventions • I suggest you use the following alternative names for registers and follow the conventional usage • $0 : always has 0 • $at : assembler temporary – never use • $v0-$v1 : expression and function results • $a0-$a3: first 4 args of a function • $t0-$t9: temporaries – not preserved in func. • $s0-$s8: Saved – preserved in functions • $k0-$k1: OS – do not use • $gp: global pointer – usage later • $sp: stack pointer • $ra: return address