 |
OpenVMS Calling Standard
3.5.2 Default Procedure Signature
In certain cases, a standard default procedure signature representing a
common combination of characteristics is encoded in a special manner.
(For example, see the descriptions of PDSC$W_SIGNATURE_OFFSET in
Sections 3.4.1 and 3.7.4.)
In the OpenVMS Alpha environment, procedure signatures are used only to
effect interoperation between native OpenVMS Alpha and translated VAX
VMS or OpenVMS VAX images. Default procedure signature characteristics
are defined for each of the two possible call situations.
For an OpenVMS Alpha procedure that is callable from a translated VAX
procedure, a default procedure signature implies the following
characteristics about the expected parameters and result of a call to
that procedure:
- The number of parameters passed is contained in the AI (R25)
register (taken from the count in the VAX argument list).
- All parameters (if any) are 32-bit sign extended (RASE$K_RA_I32 for
register arguments, MASE$K_MA_I32 for memory arguments).
- The function result (if any) is 32-bit sign extended
(PSIG$K_FR_I32).
For a bound procedure used as a jacket to effect a call into a
translated image, a default procedure signature implies the following
characteristics about the actual parameters and the expected result
from a call to that translated procedure:
- The number of parameters passed is contained in the AI (R25)
register.
- The register parameters (if any) are described in the AI register.
- The memory parameters (if any) are 32-bit sign extended
(MASE$K_MA_I32).
- The function result (if any) is 32-bit sign extended
(PSIG$K_FR_I32).
3.6 Procedure Call Chain
Except for the first invocation in a thread, there is always an
invocation that was previously considered to be the current
procedure invocation. The current procedure invocation,
together with the previous current procedure invocations, together with
all successive previously current procedure invocations, all the way
back to the first invocation in the thread, make up a logical list of
procedure contexts referred to as the call chain. The
current procedure invocation is always considered to be the first
procedure invocation in this logical list and the first procedure
invocation executed in the thread is always the last procedure
invocation in the list. The register values of all nonscratch registers
at the time of the currently active call in a procedure invocation can
be determined by walking the call chain and retrieving the procedure
invocation context for that invocation. A procedure is called an
active procedure (active invocation) while it exists
on the call chain.
The call chain and its supporting data are used by code that implements
various aspects of the calling standard such as call returns and
procedure unwinding.
3.6.1 Current Procedure
In this calling standard, R29 is the frame pointer (FP) register that
defines the current procedure.
Therefore, the current procedure must always maintain in FP
one of the following pointer values:
- Pointer to the procedure descriptor for that procedure.
- Pointer to a naturally aligned quadword containing the address of
the procedure descriptor for that procedure. For purposes of finding a
procedure's procedure descriptor, no assumptions must be made about the
quadword location. As long as all other requirements of this standard
are met, a compiler is free to use FP as a base register for any
arbitrary storage, including a stack frame, provided that while the
procedure is current, the quadword pointed to by the value in FP
contains the address of that procedure's descriptor.
At any point in time, the FP value can be interpreted to find the
procedure descriptor for the current procedure by examining the value
at 0(FP) as follows:
- If 0(FP)<2:0> = 0, then FP points to a quadword that contains
a pointer to the procedure descriptor for the current procedure.
- If 0(FP)<2:0> <> 0, then FP points to the procedure
descriptor for the current procedure.
By examining the first quadword of the procedure descriptor, the
procedure type can be determined from the PDSC$V_KIND field.
The following code is an example of how the current procedure
descriptor and procedure type can be found:
LDQ R0,0(FP) ;Fetch quadword at FP
AND R0,#7,R28 ;Mask alignment bits
BNEQ R28,20$ ;Is procedure descriptor pointer
LDQ R0,0(R0) ;Was pointer to procedure descriptor
10$: AND R0,#7,R28 ;Do sanity check
BNEQ R28,20$ ;All is well
;Error - Invalid FP
20$: AND R0,#15,R0 ;Get kind bits
;Procedure KIND is now in R0
|
IF PDSC$V_KIND is equal to PDSC$K_KIND_FP_STACK, the current procedure
has a stack frame.
If PDSC$V_KIND is equal to PDSC$K_KIND_FP_REGISTER, the current
procedure is a register frame procedure.
Either type of procedure can use either type of mechanism to point to
the procedure descriptor. Compilers may choose the appropriate
mechanism to use based on the needs of the procedure involved.
3.6.2 Procedure Call Tracing
Mechanisms for each of the following functions are needed to support
procedure call tracing:
- To provide the context of a procedure invocation
- To walk (navigate) the procedure call chain
- To refer to a given procedure invocation
This section describes the data structure mechanisms. The routines that
support these functions are described in Section 3.6.3.
3.6.2.1 Referring to a Procedure Invocation from a Data Structure
When referring to a specific procedure invocation at run time, a
procedure invocation handle, shown in Figure 3-9,
can be used. Defined by constant LIBICB$K_INVO_HANDLE_SIZE, the
structure is a single-field longword called HANDLE. HANDLE describes
the invocation handle of the procedure.
Figure 3-9 Procedure Invocation Handle Format
To encode a procedure invocation handle, follow these steps:
- If PDSC$V_BASE_REG_IS_FP is set to 1 in the corresponding procedure
descriptor, then set INVO_HANDLE to the contents of the FP register in
that invocation.
If PDSC$V_BASE_REG_IS_FP is set to 0, set
INVO_HANDLE to the contents of the SP register in that invocation.
(That is, start with the base register value for the frame.)
- Shift the INVO_HANDLE contents left one bit. Because this value is
initially known to be octaword aligned (see Section 3.7.1), the result
is a value whose 5 low-order bits are 0.
- If PDSC$V_KIND = PDSC$K_KIND_FP_STACK, perform a logical OR on the
contents of INVO_HANDLE with the value 1F16, and then set
INVO_HANDLE to the value that results.
If PDSC$V_KIND =
PDSC$K_KIND_FP_REGISTER, perform a logical OR on the contents of
INVO_HANDLE with the contents of PDSC$B_SAVE_RA, and then set
INVO_HANDLE to the value that results.
Note that a procedure invocation handle is not defined for a null frame
procedure.
Note
So you can distinguish an invocation of a register frame procedure that
calls another register frame procedure (where the called procedure uses
no stack space and therefore has the same base register value as the
caller), the register number that saved the return address is included
in the invocation handle of a register frame procedure. Similarly, the
number 3110 in the invocation handle of a stack frame
procedure is included to distinguish an invocation of a stack frame
procedure that calls a register frame procedure where the called
procedure uses no stack space.
|
3.6.2.2 Invocation Context Block
The context of a specific procedure invocation is provided through the
use of a data structure called an invocation context
block. The minimum size of the block is 528 bytes and is
system defined using the constant LIBICB$K_INVO_CONTEXT_BLK_SIZE. The
size of the last field (LIBICB$Q_SYSTEM_DEFINED[n]) defined by
the host system determines the total size of the block.
The fields defined in the invocation context block are illustrated in
Figure 3-10 and described in Table 3-10.
Figure 3-10 Invocation Context Block Format
Table 3-10 Contents of the Invocation Context Block
Field Name |
Contents |
LIBICB$L_CONTEXT_LENGTH
|
Unsigned count of the total length in bytes of the context block; this
represents the sum of the lengths of the standard-defined portion and
the system-defined section.
|
LIBICB$R_FRAME_FLAGS
|
The procedure frame flag bits <24:0> are defined as follows:
LIBICB$V_EXCEPTION_FRAME
|
Bit 0. If set to 1, the invocation context corresponds to an exception
frame.
|
LIBICB$V_AST_FRAME
|
Bit 1. If set to 1, the invocation context corresponds to an
asynchronous trap.
|
LIBICB$V_BOTTOM_OF_STACK
|
Bit 2. If set to 1, the invocation context corresponds to a frame that
has no predecessor.
|
LIBICB$V_BASE_FRAME
|
Bit 3. If set to 1, the BASE_FRAME bit is set in the FLAGS field of the
associated procedure descriptor.
|
|
LIBICB$B_BLOCK_VERSION
|
A byte that defines the version of the context block. Since this block
is currently the first version, the value is set to 1.
|
LIBICB$PH_PROCEDURE_DESCRIPTOR
|
Address of the procedure descriptor for this context.
|
LIBICB$Q_PROGRAM_COUNTER
|
Quadword that contains the current value of the procedure's program
counter. For interrupted procedures, this is the same as the
continuation program counter; for active procedures, this is the return
address back into that procedure.
|
LIBICB$Q_PROCESSOR_STATUS
|
Contains the current value of the processor status.
|
LIBICB$Q_IREG[
n]
|
Quadword that contains the current value of the integer register in the
procedure (where
n is the number of the register).
|
LIBICB$Q_FREG[
n]
|
Quadword that contains the current value of the floating-point register
in the procedure (where
n is the number of the register).
|
LIBICB$Q_SYSTEM_DEFINED[
n]
|
A variable-sized area with locations defined in quadword increments by
the host environment that contains procedure context information. These
locations are
not defined by this standard.
|
3.6.2.3 Getting a Procedure Invocation Context with a Routine
A thread can obtain its own context or the current context of any
procedure invocation in the current call chain (given an invocation
handle) by calling the run-time library functions defined in
Section 3.6.3.
3.6.2.4 Walking the Call Chain
During the course of program execution, it is sometimes necessary to
walk the call chain. Frame-based exception handling is one case where
this is done. Call chain navigation is possible only in the reverse
direction (in a latest-to-earliest or top-to-bottom procedure).
To walk the call chain, perform the following steps:
- Build an invocation context block when given a program state (which
contains a register set).
For the current routine, an initial
invocation context block can be obtained by calling the
LIB$GET_CURR_INVO_CONTEXT routine (see Section 3.6.3.2).
- Repeatedly call the LIB$GET_PREV_INVO_CONTEXT routine (see
Section 3.6.3.3) until the end of the chain has been reached (as
signified by 0 being returned).
Compilers are allowed to optimize high-level language procedure calls
in such a way that they do not appear in the invocation chain. For
example, inline procedures never appear in the invocation chain.
Make no assumptions about the relative positions of any memory used for
procedure frame information. There is no guarantee that successive
stack frames will always appear at higher addresses.
3.6.3 Invocation Context Access Routines
A thread can manipulate the invocation context of any procedure in the
thread's virtual address space by calling the following run-time
library functions.
3.6.3.1 LIB$GET_INVO_CONTEXT
A thread can obtain the invocation context of any active procedure by
using the following function format:
LIB$GET_INVO_CONTEXT(invo_handle, invo_context)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_handle
|
invo_handle
|
longword (unsigned)
|
read
|
by value
|
invo_context
|
invo_context_blk
|
structure
|
write
|
by reference
|
Arguments:
|
invo_handle
Handle for the desired invocation.
|
|
invo_context
Address of an invocation context block into which the procedure
context of the frame specified by
invo_handle will be written.
|
Function Value Returned:
|
status
Status value. A value of 1 indicates success; a value of 0
indicates failure.
|
Note
If the invocation handle that was passed does not represent any
procedure context in the active call chain, the value of the new
contents of the context block is unpredictable.
|
3.6.3.2 LIB$GET_CURR_INVO_CONTEXT
A thread can obtain the invocation context of a current procedure by
using the following function format:
LIB$GET_CURR_INVO_CONTEXT(invo_context)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_context
|
invo_context_blk
|
structure
|
write
|
by reference
|
Argument:
|
invo_context
Address of an invocation context block into which the procedure
context of the caller will be written.
|
Function Value Returned:
|
None. To facilitate use in the implementation of the C language unwind
setjmp
or
longjump
function (only), the routine sets R0 to 0.
|
3.6.3.3 LIB$GET_PREV_INVO_CONTEXT
A thread can obtain the invocation context of the procedure context
preceding any other procedure context by using the following function
format:
LIB$GET_PREV_INVO_CONTEXT(invo_context)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_context
|
invo_context_blk
|
structure
|
modify
|
by reference
|
Argument:
|
invo_context
Address of an invocation context block. The given context block is
updated to represent the context of the previous (calling) frame.
For the purposes of this function, the minimum fields of an
invocation block that must be defined are those IREG and FREG fields
corresponding to registers used by a context whether the registers are
preserved or not. Note that the invocation context blocks written by
the routines specified in these sections define all possible fields in
a context block. Such context blocks satisfy this minimum requirement.
|
Function Value Returned:
|
status
Status value. A value of 1 indicates success. When the initial
context represents the bottom of the call chain, a value of 0 is
returned. If the current operation completed without error, but a stack
corruption was detected at the next level down, a value of 3 is
returned.
|
3.6.3.4 LIB$GET_INVO_HANDLE
A thread can obtain an invocation handle corresponding to any
invocation context block by using the following function format:
LIB$GET_INVO_HANDLE(invo_context)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_context
|
invo_context_blk
|
structure
|
read
|
by reference
|
Argument:
|
invo_context
Address of an invocation context block. Here, only the frame
pointer and stack pointer fields of an invocation context block must be
defined.
|
Function Value Returned:
|
invo_handle
Invocation handle of the invocation context that was passed. If
the returned value is LIB$K_INVO_HANDLE_NULL, the invocation context
that was passed was invalid.
|
3.6.3.5 LIB$GET_PREV_INVO_HANDLE
A thread can obtain an invocation handle of the procedure context
preceding that of a specified procedure context by using the following
function format:
LIB$GET_PREV_INVO_HANDLE(invo_handle)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_handle
|
invo_handle
|
longword (unsigned)
|
read
|
by value
|
Argument:
|
invo_handle
An invocation handle that represents a target invocation context.
|
Function Value Returned:
|
invo_handle
An invocation handle for the invocation context that is previous
to that which was specified as the target.
|
3.6.3.6 LIB$PUT_INVO_REGISTERS
A given procedure invocation context's fields can be updated with new
register contents by calling a system library function in following
format:
LIB$PUT_INVO_REGISTERS(invo_handle, invo_context, invo_mask)
|
Argument |
OpenVMS Usage |
Type |
Access |
Mechanism |
invo_handle
|
invo_handle
|
longword (unsigned)
|
read
|
by value
|
invo_context
|
invo_context_blk
|
structure
|
read
|
by reference
|
invo_mask
|
mask_quadword
|
quadword (unsigned)
|
read
|
by reference
|
Arguments:
|
invo_handle
Handle for the invocation to be updated.
|
|
invo_context
Address of an invocation context block that contains new register
contents.
Each register that is set in the
invo_mask parameter, except SP, is updated using the
value found in the corresponding IREG or FREG field. The program
counter and processor status can also be updated in this way. (The SP
register cannot be updated using this routine.) No other fields of the
invocation context block are used.
|
|
invo_mask
Address of a 64-bit bit vector, where each bit corresponds to a
register field in the passed
invo_context. Bits 0 through 30 correspond to IREG[0]
through IREG[30], bit 31 corresponds to PROGRAM_COUNTER, bits 32
through 62 correspond to FREG[0] through FREG[30], and bit 63
corresponds to PROCESSOR_STATUS. (If bit 30, which corresponds to SP,
is set, then no changes are made.)
|
Function Value Returned:
|
status
Status value. A value of 1 indicates success. When the initial
context represents the bottom of the call chain or when bit 30 of the
invo_mask argument is set, a value of 0 is returned
(and nothing is changed).
|
Caution
While this routine can be used to update the frame pointer (FP), great
care must be taken to assure that a valid stack frame and execution
environment result; otherwise, execution may become unpredictable.
|
|