[Return to Library]  [TOC]  [PREV]  SECT--  [NEXT]  [INDEX] [Help]

3    Flow Control

This chapter contains descriptions of those aspects of the calling standard that deal with the flow of control in a program. This chapter does not discuss data manipulation. That topic is discussed in Chapter 4.

The following sections describe:


[Return to Library]  [TOC]  [PREV]  SECT--  [NEXT]  [INDEX] [Help]

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:

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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.


Table 3-1: Procedure Properties Summary
Procedure PropertyDescription
PDSC_FLAGS_REGISTER_FRAME  Indicates a register (or null) frame procedure rather than a stack frame procedure. 
PDSC_FLAGS_BASE_REG_IS_FP  Indicates that register $15 is used as a frame pointer rather than as a preserved register. 
PDSC_FLAGS_HANDLER_VALID  Indicates that there is an associated exception handler. 
PDSC_FLAGS_EXCEPTION_MODE  Indicates the error-reporting behavior expected from certain called mathematical library routines. 
PDSC_FLAGS_EXCEPTION_FRAME  Indicates that an operating system exception frame is included in the procedure's frame. 
PDSC_FLAGS_ARITHMETIC_SPECULATION  Indicates that arithmetic traps (SIGFPE) occurring in this procedure should not be delivered. This procedure was compiled with speculative execution optimization applied to arithmetic operations. Some arithmetic instructions have been moved backward, preceding conditional branches that used to control their effects. Traps caused by these moved instructions should be ignored. 
PDSC_CRD_MEMORY_SPECULATION  Indicates that memory traps (SIGSEGV, SIGBUS) occurring in this procedure should not be delivered. This procedure was compiled with speculative execution optimization applied to memory reference operations. Some memory reference instructions have been moved backward, preceding conditional branches that used to control their effects. Traps caused by these moved instructions should be ignored. 
PDSC_RPD_RSA_OFFSET  Specifies an offset from the stack pointer (SP) or frame pointer (FP) register to the register save area. 
PDSC_RPD_IMASK  Indicates a bit mask for the general registers that are saved in the stack. 
PDSC_RPD_FMASK  Indicates a bit mask for the floating-point registers that are saved in the stack. 
PDSC_RPD_ENTRY_RA  Indicates the register that contains the return address at the time of a call. 
PDSC_RPD_SAVE_RA  Indicates the register in which the return address is saved when it is not saved on the stack. 
PDSC_RPD_FRAME_SIZE  Specifies the size of the fixed part of the stack frame. 
PDSC_RPD_SP_SET  Specifies the offset from the beginning of the procedure to the instruction that changes the stack pointer. 
PDSC_RPD_ENTRY_LENGTH  Specifies the length of the procedure prologue. 
PDSC_CRD_BEGIN_ADDRESS  Specifies the address of the first instruction and entry point of the procedure. 
PDSC_RPD_HANDLER_ADDRESS  Specifies the address of an associated exception handling procedure. 
PDSC_RPD_HANDLER_DATA  Specifies supplementary per-procedure data to be passed to an associated exception handler. 


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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 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-1: Fixed Size Stack Frame Format


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.


Figure 3-2: Variable Size Stack Frame Format


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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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:

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.


Figure 3-3: Register Save Area Layout


  1. RSA.SAVED_RETURN is the contents of the return address register.

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.


Figure 3-4: Register Save Area Example



[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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.


Note

Lightweight procedures have more freedom than might be apparent. By the use of appropriate agreements with callers of the lightweight procedure as well as with procedures that the lightweight procedure calls, and by the use of unwind handlers, a lightweight procedure can modify nonscratch registers and can call other procedures.

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.



[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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:

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.)


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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:
procedure value

The calling procedure must pass the procedure value of the called procedure to the called procedure. This value can be a statically or dynamically bound procedure value. To pass this value, the calling procedure must load $27 with the procedure value before control is transferred to the called procedure. (See Section 2.2 for a description of procedure values.)

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.

return address

The calling procedure must pass the address to which control must be returned to the called procedure during a normal return from the called procedure. In most cases, the return address is the address of the instruction following the one that transferred control to the called procedure. A standard-conforming procedure must treat this register as preserved. For a standard call, the return address is passed and returned in the return address register, $26.

argument list

The argument list is an ordered set of zero or more argument items, which together include a logically contiguous structure known as an argument item sequence. In practice, this logically contiguous sequence is mapped to registers and memory in a fashion that produces a physically discontiguous argument list. In a standard call, the first six items are passed in registers $16 - $21 and/or registers $f16 - $f21. (See Section 4.1.2 for details of argument-to-register correspondence.) The remaining items are collected in a memory argument list that is a naturally aligned array of quadwords. In a standard call, this list, if present, must be passed at 0(SP).

function result

If a standard-conforming procedure is a function and the function result is returned in a register, the result is returned in $0, $f0, or $f0 - $f1. Otherwise, the function result is returned using the first argument item or else dynamically, as defined in Section 4.1.7.

stack usage

The stack pointer (SP) must at all times denote an address that has octaword alignment. (This restriction has the side effect that the in-memory portion of the argument list, if any, will start on an octaword boundary.) Note that the stack grows toward lower addresses. During a procedure invocation, SP can never be set to a value that is higher than the value of SP at entry to that procedure invocation.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.)

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).


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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:

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)

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:

bsr    $26,target+8         #Make the call

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

For example, suppose $4 contains such a computed procedure value (simple or bound). The following code fragment calls the procedure that $4 describes:

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)


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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:

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

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 mprotect(2) reference page.)


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

Except as noted, the exact instruction sequences are not specified; any instruction sequence that produces the defined effects is legal.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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

If an exception is raised or an exception occurs in the prologue
of a procedure, that procedure's exception handler, if any, will not be invoked because the procedure is not yet current. Thus, when a procedure has an exception handler, compilers must not move into the procedure prologue any code that might cause an exception which would be handled by that same handler.


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:

  1. Compute and load the procedure's GP value using the passed-in-procedure (code address) value in $27. (This code can appear elsewhere in the prologue, but provides more opportunities for linker optimizations if it appears first.)

  2. If stack space is allocated (PDSC_RPD_FRAME_SIZE is not 0), set register SP to SP - PDSC_RPD_FRAME_SIZE.

    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.

  3. For a stack frame procedure (PDSC_FLAGS_REGISTER_FRAME is 0), do both of these steps. (There is no requirement as to which step occurs first.)

    • Store the registers specified by PDSC_RPD_IMASK and PDSC_RDP_FMASK in the register save area based on PDSC_RPD_RSA_OFFSET.

    • Store the return address in the register save area.

  4. For a register frame procedure (PDSC_FLAGS_REGISTER_FRAME is 1), copy the return address to the register specified by PDSC_RPD_SAVE_RA if the value is not already there.

  5. Execute trapb, if required. (See Section 5.1.12 for details.)

  6. For a variable-size stack frame procedure (PDSC_FLAGS_BASE_REG_IS_FP is 1), copy the SP value to register FP.

    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:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.)


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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:

The following example illustrates a Stack Frame Procedure.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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:

The following example illustrates a Register Frame Procedure.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

The next sections provide the following information:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

The following reserved instruction must appear at every exit point from any procedure that uses the stack (PDSC_RPD_FRAME_SIZE is not 0):

ret  $31,($n),0001   #Return to the caller with usage hint 0001


Note

The term usage hint,
shown in the comment in the previous example, refers to the value of the branch prediction bits encoded in the ret instruction. The section on control instructions in the Alpha Architecture Reference Manual documents that these bits, <13:0> of the instruction longword, are reserved to software when the instruction is ret or jsr_coroutine.

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.


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.

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:

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.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.

  1. If the GP register has been modified or a call has been made, restore the GP register to the GOT segment pointer of the current procedure.

  2. For a variable-size stack frame procedure that does not return a value on the top of stack (PDSC_FLAGS_BASE_REG_IS_FP is 1), copy FP to SP.

  3. For a stack frame procedure (PDSC_FLAGS_REGISTER_FRAME is 0), reload any saved registers from the register save area as specified by PDSC_RPD_RSA_OFFSET. Note that, for a variable-size stack frame procedure (PDSC_FLAGS_BASE_REG_IS_FP is 1), FP is not reloaded in this step. For a fixed-size stack frame procedure (PDSC_FLAGS_BASE_REG_IS_FP is 0), $15 is reloaded if it was saved on entry.

  4. Reload the register that held the return address on entry with the saved return address, if necessary.

    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.

  5. Execute trapb, if required. (See Section 5.1.12 for details.)

  6. For a variable-size stack frame procedure (PDSC_FLAGS_REGISTER_FRAME is 0 and PDSC_FLAGS_BASE_REG_IS_FP is 1), reload $15 (FP) as would be done for any other saved register.

    After any necessary calculations, this step must be completed by exactly one instruction, as described in Section 3.2.6.1.

  7. If a function value is not being returned on the stack, restore SP to the value it had at procedure entry by adding the value in PDSC_RDP_FRAME_SIZE to SP. In some cases, the returning procedure leaves SP pointing to a lower stack address than it had on entry to the procedure, as specified in Section 4.1.7.

    After any necessary calculations, this step must be completed by exactly one instruction, as described in Section 3.2.6.1.

  8. Execute the ret $31,($n),0001 instruction, as described in Section 3.2.6.2.1, to return control to the calling procedure. In almost all cases the $n used will be $26 (the return address register) because its value must be restored before the call returns.

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

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.