HP OpenVMS Systems Documentation
OpenVMS Calling Standard
22.214.171.124 Methods for Stack Limit Checking
Since accessible memory may be available at addresses lower than those occupied by the guard region, compilers must generate code that never extends the stack past the guard pages into accessible memory that is not allocated to the thread's stack.
A general strategy is to access each page of memory down to and possibly including the page corresponding to the intended new value for the SP. If the stack is to be extended by an amount larger than the size of a memory page, then a series of accesses is required that works from higher to lower addressed pages. If any access results in a memory access violation, then the code has made an invalid attempt to extend the stack of the current thread.
This standard defines two methods for stack limit checking: implicit and explicit.
The following are two mutually exclusive strategies for implicit stack limit checking:
The stack frame format (see Section 3.4.3) and entry code rules (see Section 3.7.5) generally do not ensure access to the lowest address of a new stack region without introducing an extra access solely for that purpose. Consequently, this standard uses the second strategy. While the amount of implicit stack extension that can be achieved is smaller, the check is achieved at no additional cost.
This standard requires that the minimum guard region size is 8192 bytes, the size of the smallest memory protection granularity allowed by the Alpha architecture.
Therefore, if the stack is being extended by an amount less than or equal to 4096 and a reserve region is not required, then explicit stack limit checking is not required.
However, because asynchronous interrupts and calls to other procedures may also cause stack extension without explicit stack limit checking, stack extension with implicit limit checking must adhere to a strict set of conventions as follows:
These conventions ensure that the stack pointer is not decremented so that it points to accessible storage beyond the stack limit without this error being detected (either by the guard region being accessed by the thread or by an explicit stack limit check failure).
As a matter of practice, the system can provide multiple guard pages in the guard region. When a stack overflow is detected as a result of access to the guard region, one or more guard pages can be unprotected for use by the exception-handling facility, and one or more guard pages can remain protected to provide implicit stack limit checking during exception processing. However, the size of the guard region and the number of guard pages is system defined and is not defined by this standard.
If the stack is being extended by an amount of unknown size or by a known size greater than the maximum implicit check size (4096), then a code sequence that follows the rules for implicit stack limit checking can be executed in a loop to access the new stack region incrementally in segments lesser than or equal to the minimum page size (8192 bytes). At least one access must occur in each such segment. The first access must occur between SP and SP - 4096 because, in the absence of more specific information, the previous guaranteed access relative to the current stack pointer may be as much as 4096 bytes greater than the current stack pointer address. The last access must be within 4096 bytes of the intended new value of the stack pointer. These accesses must occur in order, starting with the highest addressed segment and working toward the lowest addressed segment.
The stack must not be extended incrementally in procedure prologues. A procedure prologue that needs to extend the stack by an amount of unknown size or known size greater than the minimum implicit check size must test new stack segments as just described in a loop that does not modify SP, and then update the stack with one instruction that copies the new stack pointer value into the SP.
The size of the reserve region must be included in the increment size
used for stack limit checks, after which it is not included in the
amount by which the stack is actually extended. (Depending on the size
of the reserve region, this may partially or even completely eliminate
the ability to use implicit stack limit checking.)
If a stack overflow is detected, one of the following results:
Note that if a transparent stack extension is performed, a stack overflow that occurs in a called procedure might cause the stack to be extended. Therefore, the TEB stack limit value must be considered volatile and potentially modified by external procedure calls and by handling of exceptions.
The calling program has specified no data type. The default argument for the called procedure should be the correct type.
8-bit unsigned quantity.
16-bit unsigned quantity.
32-bit unsigned quantity.
64-bit unsigned quantity.
128-bit unsigned quantity.
Byte integer (signed)
8-bit signed two's complement integer.
Word integer (signed)
16-bit signed two's complement integer.
Longword integer (signed)
32-bit signed two's complement integer.
Quadword integer (signed)
64-bit signed two's complement integer.
Octaword integer (signed)
128-bit signed two's complement integer.
32-bit F_floating quantity representing a single-precision number.
64-bit D_floating quantity representing a double-precision number.
64-bit G_floating quantity representing a double-precision number.
128-bit H_floating quantity representing a quadruple-precision number.
Ordered pair of F_floating quantities representing a single-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
Ordered pair of D_floating quantities representing a double-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
Ordered pair of G_floating quantities representing a double-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
Ordered pair of H_floating quantities representing a quadruple-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
32-bit IEEE S_floating quantity representing a single-precision number.
64-bit IEEE T_floating quantity representing a double-precision number.
Ordered pair of S_floating quantities representing a single-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
Ordered pair of T_floating quantities representing a single-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
128-bit IEEE X_floating quantity representing an extended-precision number.
Ordered pair of X_floating quantities representing an extended-precision complex number. The lower addressed quantity is the real part; the higher addressed quantity is the imaginary part.
String data types are ordinarily described by a string descriptor. Table 4-2 shows how the string data types are defined and encoded for OpenVMS VAX and OpenVMS Alpha environments.
A single 8-bit character (atomic data type) or a sequence of 0 to 2 16 - 1 8-bit characters (string data type).
Varying character string
A 16-bit unsigned count of the current number of 8-bit characters in the following string, followed by a string of 0 to 2 16 - 1 8-bit characters (see Section 4.5 for details). When this data type is used with descriptors, it can only be used with the varying string and varying string array descriptors, because the length field is interpreted differently from the other 8-bit string data types. (See Sections 4.5, 5.8, and 5.9 for further discussion.)
|DSC$K_DTYPE_NU||15||Numeric string, unsigned|
|DSC$K_DTYPE_NL||16||Numeric string, left separate sign|
|DSC$K_DTYPE_NLO||17||Numeric string, left overpunched sign|
|DSC$K_DTYPE_NR||18||Numeric string, right separate sign|
|DSC$K_DTYPE_NRO||19||Numeric string, right overpunched sign|
|DSC$K_DTYPE_NZ||20||Numeric string, zoned sign|
Aligned bit string
A string of 0 to 2 16 - 1 contiguous bits. The first bit is bit <0> of the first byte, and the last bit is any bit in the last byte. Remaining bits in the last byte must be 0 on read and are cleared on write. Unlike the unaligned bit string (VU) data type, when the aligned bit string (V) data type is used in array descriptors, the ARSIZE field is in units of bytes, not bits, because allocation is a multiple of 8 bits.
Unaligned bit string
The data is 0 to 2 16 - 1 contiguous bits located arbitrarily with respect to byte boundaries. See also aligned bit string (V) data type. Because additional information is required to specify the bit position of the first bit, this data type can be used only with the unaligned bit string and unaligned bit array descriptors (see Sections 5.10 and 5.11).
Table 4-3 shows how miscellaneous data types are defined and encoded for the OpenVMS VAX and OpenVMS Alpha environments.
|+DSC$K_DTYPE_ZI||22||Sequence of instructions|
|+DSC$K_DTYPE_ZEM||23||Procedure entry mask|
This data type allows a descriptor to be a data type; thus, levels of descriptors are allowed.
Bound procedure value (for VAX environment only)
A two-longword entity in which the first longword contains the address of a procedure entry mask and the second longword is the environment value. The environment value is determined in a language-specific manner when the original bound procedure value is generated. When the bound procedure is called, the calling program loads the second longword into R1. When the environment value is not needed, this data type can be passed using the immediate value mechanism. In this case, the argument list entry contains the address of the procedure entry mask and the second longword is omitted.
Bound label value
A two-longword entity in which the first longword contains the address of an instruction and the second longword is the language-specific environment value. The environment value is determined in a language-specific manner when the original bound label value is generated.
Absolute date and time
A 64-bit unsigned, scaled, binary integer representing a date and time in 100-nanosecond units offset from the OpenVMS operating system base date and time, which is 00:00 o'clock, November 17, 1858 (the Smithsonian base date and time for astronomical calendars). The value 0 indicates that the date and time have not been specified, so a default value or distinctive print format can be used.
Note that the ADT data type is the same as the OpenVMS date format for positive values only.