|
HP OpenVMS systems documentation |
Previous | Contents | Index |
In some cases, it is desirable to maintain a stack reserve region, which is a minimum-sized region that is immediately above a thread's guard region. A reserve region may be desirable to ensure that exceptions or asynchronous system faults (ASTs) have stack space to execute on a thread's stack, or to ensure that the exception dispatcher and any exception handler that it might call have stack space to execute after detection of an invalid attempt to extend the stack.
This standard does not require a reserve region.
3.9.1.3 Methods for Stack Limit Checking
Because 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.
An access can be performed by using either a load or a store operation; however, be sure to use an instruction that is guaranteed to make an access to memory. For example, do not use an LDQ R31,* instruction, because the Alpha architecture does not allow any memory access, even a read access, whose result is discarded because of the R31 destination. |
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.6.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.
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.
A more optimal strategy is:
A simple algorithm that is consistent with this requirement (but achieves up to twice the minimum number of accesses) is to perform a sequence of accesses in a loop starting with the previous value of SP, decrementing by the minimum no-check extension size (4096) to, but not including, the first value that is less than the new value for the stack pointer. |
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.
An explicit stack limit check can be performed either by inline code that is part of a prologue or by a run-time support routine that is tailored to be called from a procedure prologue. |
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.)
3.9.1.4 Stack Overflow Handling
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.
To support interoperation between images built from native OpenVMS Alpha code and images translated from OpenVMS VAX code, native Alpha compilers can optionally generate information that describes the parameters and result of a procedure. Similarly, for interoperation between images built from native OpenVMS I64 code and images translated from VAX or Alpha code, I64 compilers can also optionally generate information that describes the parameters and result of a procedure. This auxiliary information is called signature information.
Translated VAX code on Alpha and I64 systems uses VAX argument list and function return conventions as described in Section 2.4 and Section 2.5.
Translated Alpha code on I64 systems uses Alpha argument list and function return conventions as described in Chapter 3.
The following sections describe the conventions for using signature information to control the passing of arguments and returning a function value when a native procedure passes control to a translated procedure and vice versa.
The Translated Image Executive (TIE) is the user-mode support facility (itself a sharable image) that performs the following functions:
OpenVMS compilers for Alpha and I64 provide a compilation option that causes signature information to be included in the resulting object file. To support interoperation between OpenVMS native and translated code, the native code must contain signature information.
With one exception related to indirect calls (see Section 5.1.1.3 and Section 5.1.2.3), code generation is not affected by the presence or absence of translated code support.
The operation of translated images on OpenVMS Alpha and I64
systems is very similar, though different in certain details.
5.1.1 Translated VAX Images on Alpha Systems
When a VAX image is translated to an Alpha image, the VAX registers
R0--15 are represented using the lower half of the corresponding Alpha
registers R0--15 at call interface boundaries. No "type
conversion" is performed in making parameters from either native
or translated code available to each other.
5.1.1.1 Direct Calls From Translated to Native Code
When the TIE encounters a call in translated code that passes control to native Alpha code, it obtains signature information for the target procedure using the PDSC$W_SIGNATURE_OFFSET field of the target procedure descriptor (see Section 3.4.1).
If the value in the PDSC$W_SIGNATURE_OFFSET is zero, then no signature information is available, the call cannot be performed, and the TIE signals an error.
Otherwise, the TIE uses the signature information to create an
appropriate Alpha argument list (in the integer registers and stack as
appropriate), then calls the native procedure. When control returns,
the TIE obtains the returned result (if any), makes it available to
translated code, and resumes translated code execution.
5.1.1.2 Direct Calls From Native to Translated Code
Calls from native Alpha code to a routine in a translated image depend on special linker and image activator support. If the linker can confirm that the target of the call is also in native code (because the target is local to the same image), then the call is resolved normally. Otherwise, the linker passes the compiler generated signature information for use by the image activator.
If the image activator can determine that the target of the call is
also in native code, then the call is resolved normally. Otherwise, the
image activator creates a bound procedure descriptor (see
Section 3.6.4) and resolves the procedure value to that descriptor.
This descriptor is setup to pass control to a special TIE entry point
which obtains the target VAX procedure value and signature information
from that same descriptor.
5.1.1.3 Indirect Calls From Native to Translated Code
If interoperation with translated images is not required, then an indirect call is made as described in Section 3.6.3. If interoperation with translated images must be considered, the procedure value (in R4 in the following example) might be the address of a VAX entry point or the address of an Alpha procedure descriptor.
A VAX entry point can be dynamically distinguished from an Alpha procedure descriptor by examining bits 12 and 13 of a VAX entry call mask, which are required to be 0 by the VAX architecture. For an Alpha procedure, bit 12 corresponds to the PDSC$V_NATIVE flag, which is required to be set in all Alpha procedure descriptors. Bit 13 corresponds to the PDSC$V_NO_JACKET flag, which is currently required to be set but reserved for enhancements to this standard in all Alpha procedure descriptors.
If the procedure value is determined to correspond to an Alpha procedure, then the call can be completed as discussed. If the procedure value is determined to correspond to a VAX procedure, then the call must be completed using system TIE facilities that will effect the transition into and out of the code of the translated image.
Example 5-1 illustrates a code sequence for examining the procedure value.
Example 5-1 Code for Examining the Procedure Value |
---|
LDL R28,0(R4) ;Load the flags field of the target PDSC MOV #AI_LITERAL,R25 ;Load Argument Information register SRL R28,#PDSC$V_NO_JACKET,R26 ;Position jacket flag BLBC R26,CALL_JACKET ;If clear then jacket needed LDQ R26,8(R4) ;Entry address to scratch register MOV R4,R27 ;Procedure value to R27 JSR R26,(R26) ;Call entry address. back_in_line: ... ;Rest of procedure code goes here TRANSLATED: ;Generated out of line, R2 contains a LDQ R26,N_TO_T_LKP(R2) ;Entry address to scratch register LDQ R27,N_TO_T_LKP+8(R2) ;Load procedure value MOV R4,R23 ;Address of routine to call to R23 JSR R26,(R26) ;Call jacket routine BR back_in_line ;Return to normal code path CALL_JACKET: ; SRL R28,#PDSC$V_NATIVE,R28;Jacketing for translated or native? LDA R24,PSIG_OUT(R2) ;Pass address of our argument ; signature information in R24 BLBC R28,TRANSLATED ;If clear, then translated jacketing (Native Jacketing Reserved for Future Use) BR back_in_line ;Return to normal code path |
In Example 5-1, TIE jacketing functionality is provided by the SYS$NATIVE_TO_TRANSLATED routine. This system procedure is called with the actual arguments for the target procedure in their normal locations (as though the target procedure were an Alpha procedure) and with two additional, nonstandard arguments:
The conventions just described are normally accomplished using the
special service routine OTS$CALL_PROC.
The actual parameters to the target function are passed to
OTS$CALL_PROC as though the target routine is native code that is being
invoked directly. In addition, OTS$CALL_PROC receives two additional
parameters in registers R23 and R24 as described above for
SYS$NATIVE_TO_TRANSLATED.
5.1.2 Translated Images on I64 Systems
When a VAX or Alpha image is translated to an I64 image, the VAX or Alpha registers become associated with I64 registers for the purpose of making a call according to the following mapping:
VAX/Alpha Register | I64 Register |
---|---|
R0 | R8 |
R1 | R9 |
In the case of a VAX image, the lower half of the corresponding I64 register is used.
For example, at the time of a call from an Alpha to an I64 image, the contents of the Alpha R1 register become the initial contents of the I64 R9 register when native execution begins. Similarly, at the time of a call from an I64 image to a VAX image, the contents of the lower half of the I64 R8 register become the initial contents of the VAX R0 register.
For calls between a translated VAX and a translated Alpha image on I64 systems, the rules for calls between translated VAX and native Alpha images apply and make use of signature information in the translated Alpha image.
OpenVMS I64 implements a static mapping that:
However, the means for creating and accessing this mapping is not part of this calling standard.
It is not possible for dynamically generated non-native code to be
reflected in this mapping. As a result, OpenVMS does not support
translated images that dynamically generate non-native code and call
the in-memory result.
5.1.2.1 Calls From Translated to Native I64 Code
When the TIE encounters a call in translated code that passes control to native I64 code, it obtains signature information for the target routine from the function descriptor for that routine.
If the value in the signature information field is zero, then no signature information is available, the call cannot be performed, and the TIE signals an exception.
Otherwise, the TIE uses the signature information to create an appropriate I64 argument list (in the stacked registers and memory stack as appropriate), then calls the target native function. When control returns, the TIE obtains the returned result (if any), makes it available to the translated code, and resumes translated code execution.
To assure that any routine that can potentially be called from
translated code has either signature information or a zero indicating
the lack of signature information, it is necessary that every official
function descriptor be allocated with room for the signature
information field.
5.1.2.2 Direct Calls From Native I64 Code to Translated Code
Calls from native I64 code to a routine in a translated image depend on special linker and image activator support. If the linker can confirm that the target of a call is also in native code (because the target is local to the same image), then the call is resolved normally. Otherwise, the linker creates an import stub and an associated local function descriptor in the linkage table in the normal way. However, in this case the local function descriptor must be a jacket function descriptor, as described in the following paragraphs.
The linker also passes through the compiler generated signature information for use by the image activator. If the image activator can determine that the target of a call is also in native code, then the jacket function descriptor is initialized as for a simple function descriptor (the extra space in the jacket descriptor is unused). Otherwise, the image activator initializes the jacket function descriptor so that the call using that descriptor will transfer control into the TIE.
A jacket function descriptor is similar to a bound function descriptor (see Section 4.7.7) except that it initially transfers control to an entry point in the TIE. The TIE uses the signature information field together with other information in the descriptor to construct an appropriate parameter list for the translated code and effects the transfer of control into that code. When the call completes, control returns to the TIE, which sets up the return value for the native code and returns to normal execution.
A jacket function descriptor consists of the following fields:
More complete details are beyond the scope of this Standard.
Calls made by translated code to other entry points in translated code
are not visible to the OpenVMS I64 calling standard. From the
outside, a call from native I64 code to translated code looks
like a single call to the TIE entry point, regardless of how many calls
are made within the translated image.
5.1.2.3 Indirect Calls From Native to Translated Code
When translated code support is not requested, the code generated for calling a dynamic function value follows the I64 conventions. In particular, the target code address and target global pointer value are obtained from the function pointer and used in the standard way ( Section 4.7.3.2.)
When translated code support is requested, the compiled code must instead call a special service routine, OTS$CALL_PROC. The actual parameters to the target function are passed to OTS$CALL_PROC as though the target routine is native code that is being invoked directly. In addition, OTS$CALL_PROC receives two additional parameters in special registers:
OTS$CALL_PROC first determines whether the target routine is part of a translated image or not using the static mapping mentioned earlier.
If the target is in native code, then OTS$CALL_PROC completes the call in a way that makes its mediation transparent (that is, control need not pass back through it for the return). The native parameters are used without modification.
If the target is in translated code, then OTS$CALL_PROC passes control to the TIE which handles the call as described in Section 5.1.2.2.
Previous | Next | Contents | Index |