A different path of execution through subB
might have called another subroutine,
which would change $ra.
Let us look at an example where
subroutines call other subroutines.
When a subroutine gets control, it
pushes the return address in $ra onto the
stack.
When it returns to its caller,
it pops the stack to get the return address it should use.
In the picture, the push and pop instructions are conceptual. In actual code, they are done with basic instructions.
QTSPIM gives
main control
(step 1).
main computes for a while
and then calls
subA
(step 2).
subA immediately pushes
the contents of
$ra
onto the stack (step 3).
The return address that subA
will use when it returns control to main
is now on the top of the stack.
subA runs for a while
and then calls
subB (step 4),
which pushes
the current contents of
$ra
onto the stack (step 5).
The return address that subB
will use
is now on the top of the stack.
Now
subB runs for a while
and then calls
subC (step 6).
which pushes
the current contents of
$ra
onto the stack (step 7).
subC computes for a while,
and then returns to its caller
by poping the return address and using
a jr $ra instruction
(step 8).
The call-chain now unwinds as each subroutine pops its return address and jumps back to its caller (steps 9 and 10).
Finally,
main
has control.
After a computing
it exits to QTSPIM. (step 11)
After subA
returns control
to main,
could main
call another subroutine?