The following sections describe:
A procedure that maintains its caller's context on the stack
A procedure that maintains its caller's context in registers
A procedure that executes in the context of its caller
Some procedures maintain their call frame on the stack; others maintain
their call frame
entirely in registers, although they may use the stack. Simple procedures
do not necessarily maintain any call frame, but instead execute completely
in the context of their caller. The calling procedure does not need to distinguish
among these cases.
Table 3-1 briefly summarizes the properties
of a procedure that can be determined from its associated procedure descriptor.
(Some fields apply to only certain kinds of procedures.) For a complete description
of procedure descriptors, see Section 8.1.
3.1 Procedure Types
This Digital UNIX calling standard
defines three basic procedures types. A compiler may choose which type to
generate based on the requirements of the procedure in question. The standard
procedure types are:
3.1.1 Procedure Descriptor Overview
Every procedure, other than a null procedure described in Section 3.1.4,
must have a set of information associated with it that describes which type
of procedure it is and what characteristics it has. This set of information,
called a procedure descriptor,
can be thought of as a single structure,
although physically it is implemented by several structures. (See Chapter 8.)
The procedure descriptor structure is used to interpret the call chain
at
any point during a thread's execution. The structure is normally built at
compile time and is not generally accessed at run time except in support of
exception processing or other rarely used code execution.
The stack frame
of this type of procedure consists
of a fixed part (the size of which is known at compile time) and an optional
variable part. Certain optimizations can be done if the optional variable
part is not present. Compilers must be careful to recognize situations that
can effectively cause a variable part of the stack to exist in nonintuitive
ways; for example, when a called routine uses the stack as a means to return
certain types of function values. (See Section 4.1.7 for
details.)
If such a situation exists, a compiler must choose to use a variable-size
stack frame procedure when compiling the caller so that any unwind operations
can be performed correctly.
Figure 3-1
shows the format of the stack frame
for a procedure with a fixed amount of stack. This format uses SP as the
stack base register
(that is, PDCS_FLAGS_BASE_REG_IS_FP
is 0). In this case, $15 is simply another saved register and has no special
significance.
Figure 3-2
shows the format of the stack
frame for a procedure with a varying amount of stack. The format uses FP
as the stack base register; that is, PDSC_FLAGS_BASE_REG_IS_FP
is 1.
In both cases, the portion of the stack frame designated by PDSC_RPD_FRAME_SIZE must be allocated and initialized by the entry code sequence of a called
procedure with a stack frame.
Fixed temporary locations
are optional sections of the stack frame
that contain language-specific locations required by the procedure context
of some high-level languages. These locations might include, for example,
register spill areas, language-specific exception handling contexts (such
as language dynamic exception handling information), or fixed temporary locations.
If a compiler chooses, the fixed temporary locations adjacent to the
area pointed to by the frame base register added to the value of PDSC_RPD_FRAME_SIZE can be used for a special purpose referred to as the argument home
area.
The argument home area
is a region of memory
used by the called procedure for the purpose of assembling in contiguous memory
the arguments passed in registers adjacent to the arguments passed in memory,
so that all arguments can be addressed as a contiguous array. This area can
also be used to store arguments that are passed in registers if an address
for such an argument must be generated. Generally, 6 or 12 contiguous quadwords
of stack storage are allocated by the called procedure for this kind of storage.
(See Section 4.1.3 for details.)
The register save area
is a set of consecutive quadwords where the
current procedure saves and restores registers. The register save area begins
at the location pointed to by the frame base register
(as indicated
by PDSC_FLAGS_BASE_REG_IS_FP) added to the value of the contents
of PDSC_RPD_RSA_OFFSET. The result must be a quadword-aligned address.
The set of registers saved in this area contains the return address followed
by the registers specified in the procedure descriptor by PDSC_FLAGS_IMASK and PDSC_FLAGS_FMASK. The details of how to lay out and
populate the register save area are described in Section 3.1.2.2.
A compiler can use the stack temporary area
for storage of fixed local variables, such
as constant-sized data items, program state information, and dynamically sized
local variables. The stack temporary area can also be used for dynamically
sized items with a limited lifetime, such as a dynamically sized function
result or string concatenation that cannot be directly stored in a target
variable. When a procedure uses this area, the compiler must keep track of
its base and reset SP to that base in order to reclaim storage used by temporaries.
The high-address end of the stack frame is defined by the value stored
in PDSC_RPD_FRAME_SIZE added to the contents of the SP or FP register,
as indicated by PDSC_FLAGS_BASE_REG_IS_FP. The high-address end
is used to determine the value of the SP register for the predecessor procedure
in the call chain.
All registers saved in the variable portion of the register save area
must have the corresponding bit set to 1 in the appropriate procedure descriptor
register save mask. This bit must be set to 1 even if the register is not
a member of the set of registers required to be saved across a standard call.
If the bit is not set to 1, the offsets within the save area cannot be calculated
correctly.
The algorithm for packing saved registers in the quadword-aligned register
save area is as follows:
This behavior is required so that an unwind routine can properly restore
the floating-point registers without more complete type information.
A standard-conforming procedure that utilizes a register save area must
save the return address register at offset 0 in the register save area. There
is no corresponding bit in the register save mask for this register slot.
Figure 3-3 shows the layout of
the register save area.
For example, if registers $10, $11, $14, $22, $f2, and $f3 are saved
by a standard-conforming procedure, the PDSC_RPD_IMASK value is
00404C00 (hex) and the PDSC_RPD_FMASK is 0000000C (hex). The register
save area for such a procedure is packed as shown in Figure 3-4.
Such a procedure cannot save and restore nonscratch registers.
Because a procedure without a stack
frame must, therefore, use scratch registers to
maintain the caller's context; such a
procedure cannot make a standard-conforming call to any other procedure.
A procedure with a register frame can have an exception handler and
can handle exceptions in the normal way. Such a procedure can also allocate
local stack storage in the normal way, although it might not necessarily do
so.
Agreements such as these can be made by convention (as in the case of
language-support routines in the run-time library) or by interprocedural analysis.
Calls employing such agreements are, however, not standard calls, and might
not be fully supported by a debugger because it might not be able to find
the contents of the preserved registers, for example.
Because such agreements must be permanent for upward compatibility of
object code, lightweight procedures should, in general, follow the normal
restrictions.
This special case of a register frame procedure is of interest because
it has an associated special-case procedure descriptor representation. (See Section 8.1 for information about procedure descriptor representation.)
This calling standard has been designed so that the same instruction
sequence can be used to call each different type of procedure; that is, the
caller does not have to know which type of procedure is being called.
When a target routine is not loaded in memory at the beginning of execution
of a main program or shared image, the procedure value used by a caller of
that routine generally addresses some kind of stub
or jacket routine.
The purpose of a stub or jacket routine
is to perform the loading of the actual target routine. The call is completed
after this load operation.
When control actually reaches the target routine entry point, $27 must
contain the actual procedure value of the newly loaded routine as if no intermediate
processing had occurred. Subject to these constraints, the PV register can
be used freely by the stub/jacket code as a temporary register during its
own execution.
The contents of the stack,
located above the portion of the argument
list (if any) that is passed in memory, belong to the calling procedure. Because
they are part of the calling procedure, they should not be read or written
by the called procedure, except as specified by indirect arguments or language-controlled
up-level references.
The SP value might be used by the hardware when raising exceptions and
asynchronous interrupts. It must be assumed that the contents of the stack
below the current SP value and within the stack for the current thread are
continually and unpredictably modified, as specified in the Alpha
Architecture Reference Manual, and as a result of asynchronous
software actions.
If access to a GOT segment is required, two instructions in the called
procedure's prologue
will compute
the GOT pointer value (GP register contents) using ldah and lda instructions together with the passed $27 value. Because the ldah/lda pair can generate addresses only within 2 GB of $27, the code
and GOT must be within [plusmn] 2 GB of each other. Typically these instructions
are the first two in the procedure. (In certain cases, at link time these
two instructions may be replaced by nop instructions, skipped,
or removed if the linker is able to determine that they are redundant.) The
resultant pointer into the GOT segment is placed in the GP register. This
pointer can then be used by the called procedure as a base register to address
locations in the GOT.
Because a standard-conforming calling procedure must assume that the
GP register value is destroyed across a call but must itself return it with
the correct value, the code following the call must reestablish its value
before further accesses to the GOT or by the time it returns from the procedure.
(See Section 2.3.1 for information on integer registers.)
The following list describes some ways to reestablish the GP register
value:
In summary, a standard-conforming call provides the procedure value
(code address) to the called procedure (in case it needs to compute a new
GP value) and provides its own GP value to the called procedure (in case it
shares the GOT segment). Furthermore, upon return from the called procedure,
the GP value must be restored (in case the called procedure did not share
the same GOT segment).
For many calls, the called procedure shares the same GOT
segment with the caller.
In these cases, the GP register is already valid for the called procedure
at the time of the call. Several optimizations are possible in these important
cases. When one procedure calls another that shares the same GOT segment
and the first two instructions of the called procedure establish the GP, the ldah/lda pair can be skipped. Because the procedure's code address has
no other use, the caller does not need to provide it in $27. If the called
procedure's GP value that is returned in the GP register is shared with the
calling procedure, the caller does not need to reestablish the GP register
contents.
The following code fragment shows a typical standard call:
Note that other instructions may be scheduled among the ones shown here.
If the linker optimizes the call, it can be transformed to look like
the following code fragment:
The instructions that are no longer needed can be replaced by nop instructions, or deleted and compressed out. Depending on the optimizations
performed and whether the ldah/lda pair at the target is moved,
removed, or reduced to just lda, the call may or may not load $27,
may execute a jsr or a bsr, and may go to target or target+8.
For example, suppose $4 contains such a computed procedure value (simple
or bound). The following code fragment calls the procedure that $4 describes:
Bound procedure values are designed for multilanguage use. They allow
callers of procedures to use common code to call both bound and simple procedures.
When a bound procedure is called, the caller must pass some kind of
pointer to the called code to allow it to reference its up-level environment.
Typically, such a pointer is the frame pointer for that environment, though
many variations are possible. When the caller is itself executing within
that outer environment, it usually can make such a call directly to the code
for the nested procedure without recourse to any additional mechanism. However,
when a procedure value for the nested procedure must be passed outside of
that environment to a call site that has no knowledge of the target procedure,
a special bound procedure is created so the nested procedure can be called
in the same way as a simple procedure.
The procedure value of a bound procedure is defined as the address of
the first instruction of a sequence of instructions that establishes the proper
environment for the bound procedure and then transfers control to that procedure.
One direct scheme for constructing a jacket
to a bound procedure so it can be called
like a simple procedure is to allocate a sequence of instructions and data
on the stack and use the address of those instructions as the procedure value.
For example, suppose that a bound procedure named proc expects
its static link to be passed in $1. The following code fragment shows a suitable
sequence of instructions for the call:
Note that this sequence can only be created by code that is executing
within the context of the containing procedure so that the appropriate frame
pointer value is known and can easily be incorporated in the sequence illustrated.
The lifetime of this sequence is, of course, limited to the lifetime of the
stack frame in which it is allocated.
After creating the jacket instructions, it is necessary to execute an imb instruction before executing them to assure instruction cache coherence,
as described in the Alpha Architecture Reference Manual.
It might also be necessary to make the stack segment executable, for example,
by using the mprotect()
system call. (See the
Except as noted, the exact instruction sequences are not specified;
any instruction sequence that produces the defined effects is legal.
When a procedure is called, the code at the entry address must do the
following:
These actions involve the following steps, performed in the specified
order:
After any necessary calculations and stack limit checks, this step must
be completed in exactly one instruction that modifies SP. This instruction
must be the one specified by PDSC_RPD_SP_SET.
This step must be completed in exactly one instruction that modifies
the FP and that instruction must be the last instruction in the prologue.
When these steps have been completed, the executing procedure is said
to become current
for the purposes of exception handling.
The handler
for a procedure
will not be called except when that procedure is current.
The remainder of this section contains the following:
For fixed frame procedures, the frame pointer is the stack pointer.
In these cases, the stack pointer is not modified by that procedure after
the instruction in that procedure prologue specified by PDSC_RPD_SP_SET.
The following example illustrates a Stack Frame Procedure.
The following example illustrates a Register Frame Procedure.
The next sections provide the following information:
The following reserved instruction must appear at every exit point from
any procedure that uses the stack (PDSC_RPD_FRAME_SIZE is not 0):
This calling standard further requires that these bits contain the value
0001 (hex) for procedure returns and 0000 otherwise. The occurrence of the
usage hint value 0001 identifies a ret instruction as one that
is reserved for use only as described in the Alpha Architecture
Reference Manual. The ret instructions can be used
for other purposes, provided they contain a usage hint value of 0000. Those ret instructions will not be recognized and treated in a special way
for the purposes of exception handling or unwinding.
In almost all cases, the return address register ($n) used will be $26,
because it is required to be reloaded prior to the procedure return.
Thus, any lda instruction whose destination is the SP register
or any addq instruction whose destination is the SP register is
interpreted as part of a procedure exit sequence when it is immediately followed
by the reserved procedure return instruction.
A stack-resetting instruction might not be present in the case of a
procedure that returns a result on the top of the stack. However, if such
an instruction is present, it will immediately preced the reserved ret instruction.
Furthermore, for any such procedure that has PDSC_FLAGS_BASE_REG_IS_FP set to 1, the resulting sequence must immediately follow the FP reloading
instruction as in the following example:
Procedures that do not use the stack do not need to use these reserved
instruction sequences.
The unwind support code
uses the exit
code sequences to make the following assumptions about an interrupted PC value:
When a procedure has executed the first instruction of one of these
reserved sequences, the procedure becomes no longer current
for the purposes of exception handling.
The handler for a procedure will not be called in the midst of one of these
reserved instruction sequences within that procedure.
For a stack frame procedure (PDSC_FLAGS_REGISTER_FRAME is
0), load the register designated by PDSC_RPD_ENTRY_RA ($26 in a
standard call) with the return address from the register save area as specified
by PDSC_RPD_RSA_OFFSET.
For a register frame procedure (PDSC_FLAGS_REGISTER_FRAME
is 1), copy the return address from the register specified by PDSC_RPD_SAVE_RA to the register designated by PDSC_RPD_ENTRY_RA.
After any necessary calculations, this step must be completed by exactly
one instruction, as described in Section 3.2.6.1.
After any necessary calculations, this step must be completed by exactly
one instruction, as described in Section 3.2.6.1.
Note that the called routine does not adjust the stack to remove any
arguments passed in memory. This responsibility falls to the calling routine,
which can choose to defer removal of arguments because of optimizations or
other considerations.
3.1.2 Stack Frame Procedure
A stack frame procedure is one that allocates space for and saves its caller's context
on the stack.
This type of procedure is sometimes called
a "heavyweight procedure"
because of the cost of storing this
context in memory. These procedures can save and restore registers and may
make standard calls to other procedures.3.1.2.1 Stack Frame Format
Even though the exact
contents of a stack frame
are determined by the compiler,
there are certain properties common to all stack frames. There are two basic
types of stack frames: fixed-size and variable-size. Some parts of the stack
frame are optional and occur only as required by the particular procedure.
In the figures, brackets ([ ]) surrounding a field's name indicate that the
field is optional.
Figure 3-1: Fixed Size Stack Frame Format
Figure 3-2: Variable Size Stack Frame Format
3.1.2.2 Register Save Area
The layout of the frame
of a stack frame procedure contains a substructure called the register save area. This section describes how this area is defined
and populated.Note
Figure 3-3: Register Save Area Layout
Figure 3-4: Register Save Area Example
3.1.3 Register Frame Procedure
A register frame procedure does not maintain a call frame on the stack and must, therefore,
save its caller's context in registers. This type of procedure is sometimes
referred to as a "lightweight procedure"
because of the relatively fast way
it saves the call context.Note
3.1.4 Null Frame Procedure
A null frame procedure is a simple case of a register frame procedure. The null frame
procedure has the following characteristics:
3.2 Transfer of Control
A standard-conforming procedure call
can use any sequence of instructions that presents the called routine with
the required environment. (See the standard call definition in Section 1.5.)
However, the majority of standard-conforming external calls is performed with
a common sequence of instructions and conventions. This common set of call
conventions is so pervasive that it is included as part of this standard in Section 3.2.1. 3.2.1 Call Conventions
The following call conventions describe
the rules and methods used to communicate certain information between the
caller and the called procedure during invocation and return:
3.2.2 Linkage
When a standard procedure is called, the caller must provide
the procedure value (code address)
of the called
procedure in $27 so the called procedure can compute the address of the global
offset table (GOT) segment.
(See Section 2.5 for information about the global offset table.)3.2.3 Link-Time Optimization
The design of this calling standard assumes
and expects that the normal call conventions described here will be improved
by certain optimizations performed at link time in response to compiler-provided
control information. However, the specified calling conventions will behave
correctly even in the absence of link-time optimization.
ldq $27,target_ptr(GP) #Load procedure value (entry address)
jsr $26,($27) #Call with return address in $26
ldah GP,fix_hi($26) #Reload GP value
lda GP,fix_lo(GP)
bsr $26,target+8 #Make the call
3.2.4 Calling Computed Addresses
Most calls are made to a fixed
address whose value is already determined by the time the program starts execution.
There are, however, certain cases that cause the exact address not to be
determined until the code is actually executed. In these cases, the procedure
value representing the procedure to be called will be computed in a register.
mov $4,$27 #Move the procedure value to $27.
jsr $26,($4) #Call the entry address.
ldah GP,fix_hi($26) #Reload the GP register.
lda GP,fix_lo(GP)
3.2.5 Bound Procedure Values
There are two distinct
classes of procedures:
A simple procedure
is one that does not need
direct access to the stack
of its execution environment.
A bound procedure is one that must have direct access
to the stack of its execution environment, typically so that it can reference
an up-level variable or perform a nonlocal goto. Simple procedures and bound
procedures have associated procedure descriptors, as described earlier in
this chapter.
ldq $1,24($27) #Fetch the up-level pointer to $1
ldq $27,16($27) #Fetch the address of the bound
# procedure code
jmp ($27) #Transfer to the bound procedure
nop #Include a filler to align following
# data
quadword-holding-procedure-code-address
quadword-holding-static-link
mprotect
(2) reference
page.)3.2.6 Entry and Exit Code Sequences
The following sections describe the
steps that must be executed in procedure entry and exit sequences. These
conventions must be followed in order for the call chain to be well-defined
at every point during thread execution.3.2.6.1 Entry Code Sequence
Because the value of
the PC defines the currently executing procedure, all properties of the environment
specified by a procedure's descriptor must be valid before the first instruction
after the procedure prologue
(as defined by PDSC_RPD_ENTRY_LENGTH) is executed. In addition, none of the properties specified in the
calling procedure's descriptor may be invalidated before the called procedure
becomes current.
Thus, until the procedure becomes current,
all entry code must adhere to the following rules:
Note
3.2.6.1.1 Prologue Length
As a general rule, it is
valid to include instructions in the prologue (in addition to those that are
required) in order to take advantage of available processor cycles that are
not otherwise used. However, any such additional instructions must not cause
an exception that would need to be handled by that procedure if that exception
would be raised after the procedure became current. (An exception is considered
to not be handled by a procedure if it is known that the handler will always
resignal that exception.)3.2.6.1.2 Frame Pointer Conventions
After the procedure prologue
is completed, the register indicated by PDSC_FLAGS_BASE_REG_IS_FP
must contain the frame pointer of the stack frame. The frame pointer
is the address of the lowest-addressed
byte of the fixed portion of the stack frame
allocated by the procedure prologue. The value of
the frame pointer is the value of
PDSC_RPD_FRAME_SIZE
subtracted from the value of the stack pointer
upon procedure
entry.3.2.6.1.3 Entry Code Example for a Stack Frame Procedure
This section
contains an entry code example for a stack frame procedure. The example assumes
the following:
ldah GP, off_hi($27) #Compute the correct GP value.
lda GP, off_lo(GP)
lda SP,-SIZE(SP) #Allocate space for a new stack frame.
stq $26,16(SP) #Save the return address.
stq $9,24(SP) #Save the first integer register.
stq $10,32(SP) #Save the next integer register.
stq $11,40(SP) #Save the next integer register.
stt $f2,48(SP) #Save the first floating-point register.
stt $f3,56(SP) #Save the last floating-point register.
trapb #Force any pending hardware exceptions
# to be raised.
#The called procedure is now the current procedure.
3.2.6.1.4 Entry Code Example for a Register Frame Procedure
This section
contains an entry code example for a register frame procedure. The example
assumes the following:
ldah GP, off_hi($27) #Compute the correct GP value.
lda GP, off_lo(GP)
lda SP,-SIZE(SP) #Allocate space for a new stack frame.
#The called procedure is now the current procedure.
3.2.6.2 Exit Code Sequence
The end of procedure
entry code can be determined easily by using a PC value together with the PDSC_RPD_ENTRY_LENGTH value. Because there can be multiple return points
from a procedure, detecting that a procedure exit sequence is being executed
is not as straightforward. Unwind support routines must be able to detect
if the stack pointer
has been reset and if not, know how to reset it. The exit sequence can
be detected by requiring a reserved instruction sequence.3.2.6.2.1 Reserved Instruction Sequence for a Procedure Exit
To allow the
stack to be properly restored during an unwind,
a reserved instruction
or sequence of instructions must be used. None of these sequences can be used
in any other way.
ret $31,($n),0001 #Return to the caller with usage hint 0001
Note
For any such procedure that does not return a value on the stack, the ret instruction must be immediately preceded by either of the two reserved
stack resetting instructions.
The following examples show the two different
reserved stack-resetting instructions:
lda SP,* #Reset the stack.
ret $31,(*),0001 #Return to the caller with usage hint.
addq *,*,SP #Reset the stack.
ret $31,(*),0001 #Return to the caller with usage hint.
ldq FP,* #Restore the FP.
lda SP,* #Or addq *,*,SP to reset the stack.
ret $31,(*),0001 #Return to the caller with usage hint.
Thus, any ldq instruction whose destination is the FP register
($15) is interpreted as part of a procedure exit sequence when it is immediately
followed by the reserved procedure return instruction or by a stack resetting
instruction that is in turn immediately followed by the reserved procedure
return instruction.3.2.6.2.2 Exit Code Sequence Steps
When a procedure returns,
the exit code must restore the caller's context, synchronize any pending hardware
exceptions, and make the calling procedure current
by returning control to it. The following
list contains the exit code sequence steps. The program performs step 1,
followed by steps 2 through 5 in any order, followed by steps 6 through 8
in exact order.
3.2.6.2.3 Exit Code Example for a Stack Frame Procedure
The following
example shows the return code sequence for the stack frame procedure example
in Section 3.2.6.1.3. This code fragment assumes
that the computed GP value was saved in the preserved register $11:
mov $11,GP #Restore this routine's GP value.
ldq $26,16(SP) #Get the return address.
ldq $9,24(SP) #Restore the first integer register.
ldq $10,32(SP) #Restore the next integer register.
ldq $11,40(SP) #Restore the next integer register.
ldt $f2,48(SP) #Restore the first floating-point register.
ldt $f3,56(SP) #Restore the last floating-point register.
trapb #Force any pending hardware exceptions to be
# raised.
lda SP,SIZE(SP) #Restore the SP.
ret $31,($26),0001 #Return to the caller with the usage hint.
3.2.6.2.4 Exit Code Example for a Register Frame Procedure
The following
example shows the return code sequence for the register frame procedure example
in Section 3.2.6.1.4.
lda SP,SIZE(SP) #Restore the SP.
ret $31,($26),0001 #Return to the caller with the usage hint.