Skip to content

5. Functions

Functions! Now we must learn some convections (arguments, return values, flow in/out, contracts) before we start learning functions.

Alt text

Every program's instructions are in memory, so they have addresses.

The program counter (PC) holds the address of the next instruction to run and is incremented by a word.

Alt text

With the first image, we just defined some basic terms. Let's see how the functions flow.

Alt text

MIPS

To call a function, we use jump and link

# void main() {
#   func();
# }
main:
    jal func

Alt text

All jal does is jumps to a new location, and makes a link back to the old one in the ra (return address) register.

So now let's return back to the main function.

# void main() {
#   func();
# }
# void func() {
#   return;
# }
main:
    jal func

func:
    jr ra

The jump to address in register (ra) just copies ra into the pc.

Alt text

Arguments and Return Values

a0-a3 are the argument registers.

v0-v1 are the return value registers.

Danger

USE THESE CONVECTIONS, YOU WILL LOSE POINTS IF YOU DON'T!!!!

ALWAYS pass arguments in a-registers

ALWAYS return arguments in v-registers

Calling a Function

Functions are like black boxes, you only need to know inputs and what it will spit out.

Alt text

li a0, 3
li a1, 5
jal add_nums
move a0, v0
li v0, 1
syscall

This should output 8.

Writing a Function

# int add_nums(int x, int y) { return x + y; }
add_nums:
    add v0, a0, a1
    jr ra

Convention

Remember the conventions above about the return and arguments values? Well, you also need to keep in mind that some registers are saved and unsaved.

alt text

What a minute, how do we save the saved registers so we do not change them when we need to use them in our function. Use the stack

The Stack

In CS 0445, the stack was one of our data structures that we covered. We imagined it growing upward, however, in memory it grows downward because of the heap.

To push elements, you need to subtract the stack pointer and store the word at that address (or just use the pseudo operation).

# push ra
subi sp, sp, 4
sw ra, (sp)

And to pop elements, you need to load the word and add to the stack pointer (or just use the pseudo operation).

# pop ra
lw ra, (sp)
addi sp, sp, 4

How to Save the Saved Registers

Below is an example function of spoon that uses s0:

spoon:
    # function prologue
    push ra
    push s0

    # code here

    # function epilogue
    pop s0
    pop ra
    jr ra

Next Page →