Professional Documents
Culture Documents
03-Subroutines and Stacks
03-Subroutines and Stacks
??
…
incrementBy1: ??
??
addi $1, $1, 1
??
jr $ra ??
??
…
$1 = ? $ra = ?
Memory (RAM)
WRAMP Subroutines: Example 2
Address 32 bits
jr $ra ??
… ??
incrementBy1: ??
addi $1, $1, 1 ??
jr $ra …
Memory (RAM)
Multiple Subroutines
• WRAMP only has one return address register.
• Calling another subroutine will overwrite its value.
• If that happens, we lose the original value and
hence cannot return to the original caller.
• We become lost
Solution?
• We could save the value of $ra before using jal
• How about choosing a register that we aren’t using,
and simply store a copy of $ra there?
• Example: we’re not using $9 yet…
incrementBy2:
add $9, $0, $ra #copy $ra to $9
jal incrementBy1 #overwrites $ra
jal incrementBy1
add $ra, $0, $9 #copy $9 back to $ra
jr $ra #return to caller!
A Good Solution?
• Not really…
• We would quickly run out of registers for anything but
trivial programs.
• Does not easily support recursion.
• Sometimes we don’t actually know which registers are
being used elsewhere.
• What if we link with someone else’s code/library?
• Saving the return address to another register is not
a general solution.
Diversion: Stacks
“jal talkAboutStacks”
Stacks
• Last In, First Out (LIFO).
• Often used in programming when
data will need to be used in the
reverse order to its creation.
• Only two operations are supported:
• Push an item onto the top of the stack
• Pop (retrieve) an item from the top of
the stack
Stack Implementation
• A stack can be implemented in several ways,
including the use of:
• An array
• A linked list
• With an array implementation, we need to keep
track of the top of the stack.
• A pointer is a convenient way to do this.
Pointers
• Pointers are variables that hold an address rather
than a value.
• Can be stored in registers or memory.
• If a register/memory location holds the address of
another variable, we can say it points to that variable
• E.g. “Register $1 points to address 2” 0
1
• What if we increment $1 by 1? 2
$1 2 3
4
5
Memory (RAM)
Pointers
• Pointers are variables that hold an address rather
than a value.
• Can be stored in registers or memory.
• If a register/memory location holds the address of
another variable, we can say it points to that variable
• E.g. “Register $1 points to address 2” 0
1
• What if we increment $1 by 1? 2
$1 3 3
4
5
Memory (RAM)
Pointers
• Simple concept, but very powerful.
• In practice, they require careful management:
• Have to make sure they always point to something valid,
otherwise very bad things can happen.
• Can have pointers to pointers to pointers…
• “Dangerous” if not used correctly:
• Can point to any memory within your process.
• Be careful not to corrupt the wrong areas of memory.
• For that reason, many languages like C# and Java do not
provide direct support for pointers.
Example: Push
Stack, initially empty Stack, after “PUSH 20”
$sp $sp
20
$sp $sp
10
5 5
20 20
Example: Pop
Before “POP” After “POP”
$sp $sp
10 10
5 5
20 20
Note: popping an item off the stack means moving the pointer to the second-to-top
item. There is no need to explicitly delete the data, because it will get overwritten in
the next push.
Example: Pop (again)
Before a second “POP” After a second “POP”
$sp $sp
10 10
5 5
20 20
WRAMP Implementation 31 0
0x00000
0x00001
Program
• The system stack is 0x00002 Instructions
• Something else?
Saving Registers using the Stack
subroutine:
subui $sp, $sp, 1 #Push value of $ra
sw $ra, 0($sp) #onto the stack
# We are now able to use $5, $6, $7, and jal ($ra)
# freely without losing their previous values
Parameters to be
passed to subroutines
called by this subroutine
Register values, saved
before being modified
by this subroutine
Local variables used
by this subroutine
$sp points to the top of this stack frame, i.e. the lowest
memory address that is part of this stack frame.
Stack Frame
return result;
}
= 2 + 3 + 0
= 5
multiply:
subui $sp, $sp, 5
Example Subroutine sw
sw
$4, 2($sp) # result
$5, 3($sp) # i
sw $ra, 4($sp)