Function Calls
Volume Number: 10
Issue Number: 6
Column Tag: Powering UP
PowerPC Function Calls 
It helps to know all that stuff that compilers take for granted.
By Richard Clark, General Magic
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Most RISC processors, including the PowerPC, use a different method for calling
procedures than CISC processors do. Most CISC processors make use of the stack for
passing parameters, holding temporary variables, and storing return addresses. The
PowerPC run-time architecture performs these functions differently. Unlike the 68K
Macintosh run-time model, where multiple calling conventions are used, the PowerPC
runtime model specifies one calling convention for all code, regardless of the
programming language used. This impacts assembly-language programming and
debugging, and a very small number of high-level language programs which use
assembly language to construct a stack frame before calling a function.
This month, we’ll describe how a Power Macintosh program calls PowerPC
functions, and give some hints for locating procedure calls in compiled code. We’ll also
go into the mail bag and follow up on calling between 68K and PowerPC code.
How PowerPC calls procedures
Most RISC processors are designed to make extensive use of their registers, since
it takes less time for a processor to access an internal register than it does to access
external memory. One example of this is the PowerPC’s load/store architecture (see
Powering Up, February, 1994) which requires that all of the operands of an
instruction be loaded into registers before the operation is performed.
The Power Macintosh calling conventions are biased heavily towards the use of
registers. (See Figure 1) Both the Fixed-point and floating-point registers are divided
into “reserved” registers, parameter passing registers, and “local variable”
registers. (The General Purpose Registers are shown as 32 bits wide here, but will be
64 bits wide on 64-bit implementations of the PowerPC.)
Figure 1 - The PowerPC registers
In the simplest sort of procedure, which accepts only a small number of
parameters and which doesn’t call any other procedures (known as a “leaf
procedure”), the procedure call doesn’t ever touch memory:
/* 1 */
/* A trivial “leaf routine” */
int average (int a, int b)
{
return (a + b) / 2;
}
; The compiled version of the above routine
; Register usage:
; Register 3 = a
; Register 4 = b
; Register 5 = unused parameter register, used as scratch
;
; Register 3 is used for the function result
; The return address is in a special “link register”, not on the
stack
csect .average{PR} ; Start of the function
addc r5,r3,r4 ; R5 = a + b (and check for carry)
srawi r5,r5,1 ; Shift R5 right 1 place
addze r3,r5 ; Copy R5 to R3 and add the carry
; (addze = “add to zero extended)
blr ; return
In this example, both of the parameters were passed in parameter registers, the
intermediate value was placed in an unused parameter register, and the return result
went back in the first parameter register. Since the PowerPC uses an internal register
for return addresses, nothing had to be placed on the stack.
However, most procedures aren’t nearly this simple: they use local variables, or
call other procedures, have long parameter lists, or need to support variable
parameter lists. If a procedure has any of these attributes, it needs to create and use a
stack frame.
PowerPC stack frames
The PowerPC stack format is shown in Figure 2 . The PowerPC uses a “grow
down” stack, just as the 68K does. However, that’s where the similarity ends. Each
procedure is responsible for creating its own stack frame (unlike the 68K where, one
could argue that the caller creates the “parameter” part of a stack frame and the callee
creates the rest.) Once created, each PowerPC stack frame remains the same size - a
procedure cannot “push” a few bytes onto the stack for temporary storage Finally,
each stack frame must end with a pointer back to the previous stack frame.
[The diagrams here are “upside-down” from what you normally might see in
Macintosh documentation, but are in line with much of the documentation you’re likely
to come across. It’s a long and sordid story, and has something to do with Apple
making a deal with a certain three-letter company, but we’ll save that for another
time. When you see these diagrams, it never hurts to double-check where the top of
memory is. In this case, up is towards zero, and that’s the direction the stack grows. -
Ed stb]
Figure 2 - A single stack frame
Each stack frame may begin with a register save area. If a procedure intends to
use one of the “non-volatile” registers shown in Figure 1, it must save the old value
of the register and restore it later. These registers are saved at the “bottom” of the
stack frame. (Only the non-volatile registers should be saved at the bottom of the stack
- see “borrowing the stack” below for an explanation.)
Next comes an unstructured local variable area. The current procedure is free to
put anything it wants here, including any local variables that won’t be placed in the
non-volatile registers.
The parameter area comes next. This area is used to pass parameters to any
procedures the current procedure calls, not to hold its own parameters. (A procedure
looks into the parameter registers and its caller’s stack frame for parameters - the
reason why is given in “borrowing the stack.”) As a result, the compiler looks at all
of this procedure’s callees, and uses the size of the largest parameter list it finds. This
area is formatted according to the rules given in “passing parameters” below.
Figure 3 - The Linkage Area
The linkage area forms the end of every stack frame, and is a special data
structure used to hold a link to the previous address, the return address, and the two
non-volatile registers within the branch unit. (See Powering Up, February 1994 for
a description of the branch unit.) The current procedure always fills in the “previous
stack frame” field, and will fill in the “old return address” field if it calls another
procedure. The other fields are either filled in by the callee, or are reserved for
system use. This unusual “I’ll fill in some fields and you fill in the rest” behavior is
explained in “borrowing the stack.”
Passing Parameters
When one procedure calls another, the caller is responsible for providing the
parameter area on the stack, and places some parameters into registers and others onto
the stack. The parameters are laid out in memory (and the registers) according to a
simple set of rules:
1. Each parameter begins on a 4-byte boundary. So, a C “short” or “char” is
padded out to a 32-bit word, while pointers, integers, and long integers remain
unchanged. The compiler only does this to individual parameters - it doesn’t go
into data structures and add padding when passing them from procedure to
procedure.
2. The first eight words of parameters (reading the parameter list from left to
right) are assigned to Registers 3 through 10 (in the Fixed Point unit). If any of
these parameters are floating-point numbers, space is set aside in one or more
fixed-point registers, though the value might not actually be filled in. (See the
next rule for an explanation.)
For example, try the function:
/* 2 */
void Sample (short aShort,
long aLong,
int anInt,
float lifesaver,
double seeing,
short changed,
long shot,
long overflow);
Showing these parameters as a structure, with each of the parameters padded out
to a word (that’s a full machine word, 32 bits on the 601), the comments show which