3.2.6 Entry and Exit Code Sequences

This section describes 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.

Entry Code Sequence

Since the value of the PC defines the currently executing procedure, it must be possible using the procedure descriptor associated with that PC, as well as the instructions of the procedure itself, to recover the identity (PC) and environment of the caller. This leads to the following restriction: A standard call cannot be made from the prologue.

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 since the procedure is not current yet. This implies that if a procedure has an exception handler then compilers may not move code into the procedure prologue that might cause an exception that would be handled by that handler.

When a procedure is called, the code at the entry address must synchronize (as needed) any pending exceptions caused by instructions issued by the caller, save the caller's context, and make the called procedure current (by executing the last instruction of the procedure prologue).

This is done by performing the following actions in the order given:

  1. If stack space is allocated (FRAME_SIZE ¹ SP - FRAME_SIZE).

    After any necessary calculations and stack limit checks, this step must be completed by exactly one instruction that modifies SP.

  2. For a stack frame procedure (REGISTER_FRAME is 0): Store the return address and any registers that are being preserved in the stack frame. The stack frame reference must use SP.

    Note   If the locations allocated for saving the registers must be more than 32768 bytes away from the top of stack (for example, because the procedure contains an actual parameter list whose size exceeds 32768 bytes), then it is not possible to allocate the entire stack in a single step. In this case, the variable stack size form of stack frame must be used. (Recall that memory reference instructions in the Alpha architecture can address at most 32768 bytes relative to the contents of some general register.)

  3. Execute TRAPB if required.

  4. For a variable-sized stack frame procedure (BASE_REG_IS_FP is 1), copy register SP to register FP.

    This step must be completed by exactly one instruction that modifies FP.

When the above 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.

It is possible for a single routine to have more than one entry point, hence more than one entry code sequence of instructions. When this occurs, all of the entry code sequences must be equivalent in the sense that after execution leaves each prologue, any one of the entry code sequences can be used for exception-handling purposes regardless of which entry code sequence was actually used to enter the routine. The fixed-size stack allocation, where specific registers are saved in the stack frame, and so on, are all properties of the routine as a whole, not a particular entry point, and every entry point must establish the same run-time frame before completing the prologue. (In general, after execution completes one of the prologues, control passes into code that is common to all entry points and it is not possible to tell which entry was actually called.)

Unwindable Entry Code Instructions

For each of the steps described above, there are specific instructions or sequences of instructions that must be used. These are the only instructions that are interpreted when unwinding a stack frame for purposes of exception dispatching or stack walking. (Such prologue interpretation is sometimes called reverse execution. See Getting a Procedure Invocation Context with a Routine for related discussion.)

  1. Allocate stack

    Let N be the number of bytes to allocate for the fixed part of the stack. The simpler case occurs when the size of the extension does not exceed the value of MAX_NOCHK_EXTEND, 4096, and can therefore be represented in the 16-bit offset field of an LDA instruction. In this case, use

    LDA   SP, -N(SP)  

If the previous case does not apply, then use the sequence

load  Rx, N  
...
SUBQ  SP, Rx, SP  

where Rx is a scratch register for the procedure and load stands for one of a number of alternatives for loading the constant N into register Rx. The load of Rx and update of the stack pointer are separated by instructions that check that the stack limit is not exceeded by the allocation as described in Section 6.1, Stack Limit Checking.

The following instructions may be used to load a constant value N into a register Rx:

BIS    R31, N, Rx       ; 0 ≤? N ≤? 255

or 

ADDQ   R31, N, Rx       ; 0 ≤? N ≤? 255

or 

LDA    Rx, N(R31)       ; 0 ≤? N ≤? 32767

or 

LDAH   Rx, Hi(R31)      ; 0 ≤? Hi ≤? 32767, N = Hi*65536

or 

LDAH   Rx, Hi(R31)      ; 0 ≤? Hi ≤? 32767
LDA    Rx, Lo(Rx)       ; -32768 ≤? Lo ≤? 32767
                        ; N = Hi*65536 + Lo

In the last case, the LDAH and LDA instructions need not be contiguous.

  1. Save return address and preserved registers

    General-purpose registers that are saved on the stack must be saved using

    STQ    Rx, n(SP)  
    

    where Rx is the register being saved (including the return address register) and n is the offset in the stack for saving that register. Similarly, floating-point registers that are saved on the stack must be saved using

    STT    Fx, n(SP)  
    

    where Fx is the register being saved and n is the offset in the stack for saving that register. (Note that floating-point registers are never saved using STF, STD, STG, or STS because the called routine has no a priori information about the type of the variable contained in the register. Similarly, LDT is always used to restore a floating register.)

    Preservation of registers in this manner is not limited to just the standard preserved integer and floating-point registers.

    A register that is preserved may also be saved by moving it to a scratch register in the case of a register frame procedure.

    There are no requirements concerning the order in which registers are saved or the position within the stack frame where they are saved.

    The first use of a register that is preserved within a prologue must be to save it. The save operation may consist of a sequence of moves that start with a given register, copy the contents to other registers, and optionally store the register in the stack. (This may be necessary, for example, to temporarily preserve the return address if a routine is called in the prologue to perform stack limit checking. Note that such a called routine is necessarily nonstandard.) The last location in this sequence (whether a register or a stack location) must thereafter not be modified during the execution of the procedure. The registers involved in such a sequence (other than the last if the contents is not stored in the stack) can be used for other purposes provided, either

    In the case of the return address register (R26), the occurrence of more than one of the above instructions that reads that register in a prologue is reserved for use by the kernel. The occurrence of more than one such instruction is used in kernel routine prologues that are invoked by exceptions and traps to indicate that the associated frame is an exception frame (as defined in the Alpha System Reference Manual); see Section 7.3 for further discussion. If there is a need to use the return address value in the prologue in addition to saving it in the normal manner, then the return address value must be read from the saved location rather than directly from R26.

  2. Force pending exceptions

    The TRAPB instruction is used to ensure that any pending exceptions occur prior to the end of the prologue (prior to the routine becoming current).

  3. Initialize frame pointer register

    The frame pointer must be set using

    MOV     SP, FP  
    
  4. Move a register to another register

    A general register Rx must be moved (MOV) to another general register Ry using

    BIS     R31, Rx, Ry  
    
    or 
    
    BIS     Rx, Rx, Ry  
    
    or 
    
    BIS     Rx, R31, Ry  
    

    A floating-point register Fx must be moved to another general register Fy using

    CPYS    Fx, Fx, Fy  
    

Note   The SP register is normally "saved" and "restored" by adjusting its contents by a fixed value that is part of the instruction stream rather than by copying its contents to another register or to a location on the stack. However, a STx SP,n(SP) or MOV SP,Rx instruction is reverse executed as just described in paragraphs 2 and 5 above. It follows that these instructions can be included in a procedure prologue only if their reverse execution is in fact intended as part of restoring the SP contents. In particular, code scheduling must not allow such instructions, whose use of the SP contents is unrelated to SP maintenance, to be moved into the prologue of a procedure.

Prologue Length

As a general rule, it is valid to include instructions in the prologue in addition to those required above in order to take advantage of available processor cycles that are not otherwise used. However, to avoid undesirable reverse execution overhead during exception, dispatching or unwinding the length of the prologue should not be increased in ways that do not exploit such available cycles except possibly to include instructions that have an unusually long latency. In any case, it must not be possible for such additional instructions to cause an exception that would be handled by that procedure if that exception were raised after the procedure became current. (An exception may be considered to be not handled by a procedure if it is known a priori that the handler will always resignal that exception.)

It follows from these considerations that the length of the prologue of a procedure should typically be no larger than two instructions times the number of registers that are preserved in that procedure, in addition to those instructions that perform stack limit checking (if any). In Windows NT for Alpha Systems, there must not be more than 1024 instructions in a prologue. If a larger number is detected, then the containing program may be aborted.

Frame Pointer Conventions

After procedure prologue completion, the register indicated by BASE_REG_IS_FP must contain the frame pointer of the stack frame, which 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 FRAME_SIZE subtracted from the value of the stack pointer upon procedure entry.

For fixed frame procedures, the frame pointer is the stack pointer, which is not modified by that procedure after the instruction in that procedure prologue specified by SP_SET.

Entry Code Example for a Stack Frame

This example assumes that this is a stack frame procedure, that registers R9..R11 and F2..F3 are saved and restored, that the procedure has a static exception handler that does not reraise arithmetic traps, and that the procedure uses a fixed amount of stack (BASE_REG_IS_FP is 0).

LDA     SP,-SIZE(SP)    ;Allocate space for new stack frame  
STQ     R26,16(SP)      ;Save return address  
STQ     R9,24(SP)       ;Save first integer register  
STQ     R10,32(SP)      ;Save next integer register  
STQ     R11,40(SP)      ;Save next integer register  
STT     F2,48(SP)       ;Save first floating-point register  
STT     F3,56(SP)       ;Save last floating-point register  
TRAPB                   ;Force any pending hardware exceptions  
                        ;  to be raised
                        ;Called procedure is now the current procedure

Entry Code Example for a Register Frame

The following entry code example is for a called procedure that has no static exception handler. Both SAVE_RA and ENTRY_RA specify R26 and the procedure utilizes a fixed amount of stack storage (BASE_REG_IS_FP is 0).

LDA     SP,-SIZE(SP)       ;Allocate space for new stack frame
                           ;Called procedure is now the current procedure

Exit Code Sequence

The end of procedure entry code can be determined easily given a PC value together with the ENTRY_LENGTH value. Since there may be multiple return points from a procedure, detecting that a procedure exit sequence is being executed is not quite as straightforward. Unwind support routines must be able to detect if the stack pointer has been reset or not and, if not, how to reset it. This is done by using a reserved instruction sequence.

Reserved Instruction Sequence for 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 may be used in any other way.

The following reserved instruction must appear at every exit point from any procedure that uses stack (FRAME_SIZE ¹ 0):

RET     R31,(Rn),0001      ;Return to caller with usage hint 0001  

Note   Usage hint refers to the value of the branch prediction bits encoded in the RET instruction. The Alpha System Reference Manual documents that these bits, <13:0> of the instruction longword, are reserved to software when the instruction is RET or JSR_COROUTINE. (See Section 4.3 of the Alpha System Reference Manual.) This calling standard further requires that these bits contain the value 0001 (hex) for procedure returns and 0000 otherwise. It is the occurrence of the usage hint value 0001 that identifies a RET instruction as one that is reserved for use only as described in this section. RET instructions may be used for other purposes provided they contain a usage hint of 0000. Such RET instructions will not be recognized and treated in a special way for the purposes of exception handling or unwinding.

Furthermore, for any such procedure that does not return a value on the stack, the above instruction must be directly preceded by one of the two reserved stack resetting instructions, as in:

LDA     SP,*                ;Reset stack  
RET     R31,(*),0001        ;Return to caller with usage hint

or 

ADDQ    *,*,SP              ;Reset stack  
RET     R31,(*),0001        ;Return to caller with usage hint  

That is, 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 immediately followed by the reserved procedure return instruction. The LDA instruction must have the form LDA SP,n(Rx) if the amount by which the stack is being adjusted can be represented as the offset n. Otherwise, the latter form is used, in which case the ADDQ instruction must have the form ADDQ Rx, Ry, SP where, in particular, Ry is the name of a register rather than a literal operand.

A stack resetting instruction may not be present (in the case of a procedure that returns a result on the top of the stack). However, if present, it will occur immediately preceding the reserved RET instruction.

Furthermore, for any such procedure that has BASE_REG_IS_FP set to 1, the resulting sequence must be directly preceded by the FP reloading instruction, as in:

LDQ     FP,*                ;Restore FP  
LDA     SP,*                ;Or ADDQ *,*,SP to Reset stack  
RET     R31,(*),0001        ;Return to caller with usage hint  

That is, any LDQ instruction whose destination is the FP register (R15) 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 as described above that is immediately followed by the reserved procedure return instruction.

Procedures that do not use the stack need not use these reserved instruction sequences.

The unwind support code uses the above sequences to make the following assumptions about an interrupted PC value:

Otherwise, the registers must be restored, SP reset, and the unwind can proceed.

When a procedure has executed the first instruction of one of the reserved sequences just described, 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 in that procedure.

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.

This is done by performing the following actions:

Perform step 1, followed by steps 2 - 4 in any order, followed by steps 5 - 7 in that order.

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

  2. For a stack frame procedure (REGISTER_FRAME is 0), reload any saved registers. (For a fixed-size stack frame procedure (BASE_REG_IS_FP is 0), R15 is reloaded if it was saved on entry.)

  3. Reload the register that held the return address on entry with the saved return address if necessary. For a stack frame procedure (REGISTER_FRAME is 0), load the register designated by ENTRY_RA (R26 in a standard call) with the return address.

  4. Execute TRAPB if required.

  5. For a variable-size stack frame procedure (REGISTER_FRAME is 0 and BASE_REG_IS_FP is 1), reload R15 (FP) as for any other saved register.

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

  6. If a function value is not being returned on the stack, then restore SP to the value it had at procedure entry by adding the value that was stored in FRAME_SIZE to SP. (In some cases the returning procedure will leave SP pointing to a lower stack address than it had on entry to the procedure.)

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

  7. Execute the RET R31,(Rn),0001 instruction as described above to return control to the calling procedure.

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 may choose to defer their removal due to optimizations or other considerations.

Exit Code Example for a Stack Frame

The following is the return code sequence for the stack frame example above:

LDQ     R26,16(SP)      ;Get return address  
LDQ     R9,24(SP)       ;Restore first integer register  
LDQ     R10,32(SP)      ;Restore next integer register  
LDQ     R11,40(SP)      ;Restore next integer register  
LDT     F2,48(SP)       ;Restore first floating-point register  
LDT     F3,56(SP)       ;Restore last floating-point register  
TRAPB                   ;Force any pending hardware exceptions  
                        ;  to be raised  
LDA     SP,SIZE(SP)     ;Restore SP  
RET     R31,(R26),0001  ;Return to caller with usage hint  

Exit Code Example for a Register Frame

The following is the return code sequence for the register frame example above:

LDA     SP,SIZE(SP)     ;Restore the SP  
RET     R31,(R26),0001  ;Return to caller with usage hint