There are a whole bunch of registers, which you can think of as being in blocks
of 8. At any one time, three consecutive blocks of 8 registers are visible as
the current register window, and are labelled as %o0-%o7, %l0-%l7, and
%i0-%i7. (There is a fourth block of 8 registers, %g0-%g7, which are
global rather than being a part of the windowing arrangement.)
When you save or restore, the window moves by two blocks of 8. The
overlapping block allows for parameter and result passing. The registers
which are named %o0-%o7 in the caller are the same ones that are named
%i0-%i7 in the callee. (The two new blocks in the callee are %l0-%l7,
which are private for local use within that window, and %o0-%o7 which the
callee can use when it in turn wants to call another function.)
It's clearer with a picture:
: :
+----------------------+
| Block of 8 registers | caller's window
+----------------------+ +----------------------+
| Block of 8 registers | | %i0 - %i7 | ---------.
+----------------------+ +----------------------+ | save
| Block of 8 registers | | %l0 - %l7 | v
+----------------------+ +----------------------+ +----------------------+
| Block of 8 registers | | %o0 - %o7 | | %i0 - %i7 |
+----------------------+ +----------------------+ +----------------------+
| Block of 8 registers | ^ | %l0 - %l7 |
+----------------------+ restore | +----------------------+
| Block of 8 registers | `--------- | %o0 - %o7 |
+----------------------+ +----------------------+
| Block of 8 registers | callee's window
+----------------------+
: :
Your caller places the num argument into %o0 (in its window), then calls
you. You save to set up a new window, and so you see it in %i0 in your
window.
.rem takes two parameters. You place these in your %o0 and %o1 (in your
window), then call it. It will see them in its %i0 and %i1 (assuming it does
a save to set up a new window). It puts the answer in its %i0, which is
your %o0.
Similarly, you should put your result in your %i0; whoever called you will see it
in their %o0.