In most cases, you will not want to write entire programs in assembly
language. Instead, you will want to write most of the program in a
high-level language (like C) and only write a few procedures in
assembly language--the procedures that cannot be easily optimized in
the high-level language or that need to take advantage of special
features provided by the machine.

In this lab, we complete our presentation of the SPARC application
binary interface (ABI). The SPARC ABI is a set of conventions that
are expected to be followed by all compilers and assembly language
programmers. These conventions cover the uses of registers and the
structure of the stack frame. If you follow the conventions specified
by the SPARC ABI in your assembly language procedures, it will be
possible to call your procedures from procedures written in high-level
languages. You will also be able to call procedures written in
high-level languages from your assembly language procedures.

In Lab 10 we covered the portion of the SPARC ABI that deals
with optimized leaf procedures. In Lab 11 we covered the
conventions related to register usage for procedures that are not
implemented as optimized leaf procedures. In this lab we cover the
conventions related to the allocation and structure of stack frames.
Throughout this lab we will assume that we are not implementing an
optimized leaf procedure.

The stack pointer is stored in register %o6. This register can also
be referenced using the alias %sp. Due to the overlap of register
windows, the stack pointer for the calling procedure is always
available in register %i6. In SPARC terminology, the previous stack
pointer is called the frame pointer and can be accessed using the
alias %fp. The stack grows from addresses with larger numbers to
addresses with smaller numbers. As such, allocation of a stack frame
is implemented by subtracting a value from the current stack pointer
(actually, this usually done by adding a negative number to the stack
pointer).

As we noted in the previous two labs, registers %o0-%o5 are used
for the first six parameters passed to a procedure. If a procedure
has more than 6 parameters, the remaining parameters are passed on the
stack. SPARC procedures do not push parameters (beyond the sixth
parameter) onto the procedure call stack. Instead, they allocate
space in their stack frame for the parameters and copy parameters into
this space. This means that the called procedure will find its
parameters (beyond the sixth) in the caller's stack frame. The called
procedure can access these parameters using the frame pointer (%fp)
with positive offsets.

As a minimum, every procedure that is not implemented as an optimized
leaf procedure (i.e., any procedure that executes a save instruction)
must allocate a stack frame of at least 64 bytes. This space will be used to
store the input and local registers (%i0-%i7 and %l0-%l7)
allocated by this procedure should you run out of register windows in
a later procedure call.

Every non-leaf procedure must allocate an additional 7 words (28 bytes)
in its stack frame. The first word of this space is used to store a
``hidden'' parameter. The hidden parameter is used for procedures
that return structured values. Procedures that return simple values
use %i0 (the caller's %o0) to return the result. However, if a
procedure returns a structured value, the result may not fit in a
register. In this case, the calling procedure must allocate space
for the return value (probably in its stack frame). The calling
procedure then puts the address of this space into the hidden
parameter before making the call.

The remaining 6 words can be used by the called procedure to store the
first six arguments (the ones passed in %o0-%o5). In most cases,
the called procedure will be able to access these parameters in the
registers %i0-%i5 and will not need to store them in the caller's
stack frame. However, if the called procedure needs to take the
address of a parameter, it needs to store the parameter into memory
(you can't take the address of a register).

In addition to the regions that we have discussed, a procedure may
allocate additional stack space for: alignment (the stack pointer
should always be a multiple of 8), outgoing parameters (beyond the
sixth parameter), automatic local arrays and other automatic local
variables that don't fit in the local registers %l0-%l7,
temporaries, and floating point registers. Figure 12.2
illustrates the organization of a SPARC stack frame.