Function Calling Mips Assembly Call and Return Steps

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 • 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, -4 • To pop a value off the stack and put it into register $31, use add $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 $a 0 -$a 3 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, -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, arg 1 sw $5, 0($sp) add $sp, -4 jal myproc ⋮ myproc: sw $31, 0($sp) add $sp, -4 lw $8, 4($sp) lw $6, 0($8) #now have the value of arg 1 ⋮ sw $9, 0($8) #stored result from $9 into arg 1 add $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 $v 0 -$v 1 : expression and function results $a 0 -$a 3: first 4 args of a function $t 0 -$t 9: temporaries – not preserved in func. $s 0 -$s 8: Saved – preserved in functions $k 0 -$k 1: OS – do not use $gp: global pointer – usage later $sp: stack pointer $ra: return address
- Slides: 21