Transcript Chapter 9
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, $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