Document revision date: 19 July 1999 | |
Previous | Contents | Index |
This chapter describes the primary conventions in calling a procedure
in an OpenVMS VAX environment.
2.1 Register Usage
In the VAX architecture, there are fifteen 32-bit-wide, general-purpose
hardware registers for use with scalar and vector program operations.
This section defines the rules of scalar and vector register usage.
2.1.1 Scalar Register Usage
This standard defines several general-purpose VAX registers and their scalar use, as listed in Table 2-1.
Register | Use |
---|---|
PC | Program counter. |
SP | Stack pointer. |
FP | Current stack frame pointer. This register must always point at the current frame. No modification is permitted within a procedure body. |
AP | Argument pointer. When a call occurs, AP must point to a valid argument list. A procedure without parameters points to an argument list consisting of a single longword containing the value 0. |
R1 | Environment value. When a procedure that needs an environment value is called, the calling program must set R1 to the environment value. See bound procedure value in Section 4.3. |
R0, R1 | Function value return registers. These registers are not to be preserved by any called procedure. They are available as temporary registers to any called procedure. |
Registers R2 through R11 are to be preserved across procedure calls. The called procedure can use these registers, provided it saves and restores them using the procedure entry mask mechanism. The entry mask mechanism must be used so that any stack unwinding done by the condition-handling mechanism restores all registers correctly. In addition, PC, SP, FP, and AP are always preserved by the CALLS or CALLG instruction and restored by the RET instruction. However, a called procedure can use AP as a temporary register.
If JSB routines are used, they must not save or modify any preserved
registers (R2 through R11) not already saved by the entry mask
mechanism of the calling program.
2.1.2 Vector Register Usage
This calling standard does not specify conventions for preserved vector
registers, vector argument registers, or vector function value return
registers. All such conventions are by agreement between the calling
and called procedures. In the absence of such an agreement, all vector
registers, including V0 through V15, VLR, VCR, and VMR are scratch
registers. Among cooperating procedures, a procedure that preserves or
otherwise manipulates the vector registers by agreement with its
callers must provide an exception handler to restore them during an
unwind.
2.2 Stack Usage
Figure 2-1 shows the contents of the stack frame created for the called procedure by the CALLG or CALLS instruction.
Figure 2-1 Stack Frame Generated by CALLG or CALLS Instruction
FP always points to the call frame (the condition-handler longword) of the calling procedure. Other uses of FP within a procedure are prohibited. Unless the procedure has a condition handler, the condition-handler longword contains all zeros. See Chapter 6 for more information on condition handlers.
The contents of the stack located at addresses higher than the mask/PSW longword belong to the calling program; they should not be read or written by the called procedure, except as specified in the argument list. The contents of the stack located at addresses lower than SP belong to interrupt and exception routines; they are modified continually and unpredictably.
The called procedure allocates local storage by subtracting the required number of bytes from the SP provided on entry. This local storage is freed automatically by the return instruction (RET).
Bit <28> of the mask/PSW longword is reserved to Digital for
future extensions to the stack frame.
2.3 Calling Sequence
At the option of the calling procedure, the called procedure is invoked using the CALLG or CALLS instruction, as follows:
CALLG arglst, proc CALLS argcnt, proc |
CALLS pushes the argument count argcnt onto the stack as a longword and sets the argument pointer, AP, to the top of the stack. The complete sequence using CALLS follows:
push argn . . . push arg1 CALLS #n, proc |
If the called procedure returns control to the calling procedure, control must return to the instruction immediately following the CALLG or CALLS instruction. Skip returns and GOTO returns are allowed only during stack unwind operations.
The called procedure returns control to the calling procedure by
executing the RET instruction.
2.4 Argument List
The argument list is the primary means of passing information to and receiving results from a procedure.
2.4.1 Format
Figure 2-2 shows the argument list format.
Figure 2-2 Argument List Format
The first longword is always present and contains the argument count as an unsigned integer in the low byte. The 24 high-order bits are reserved to Digital and must be zero. To access the argument count, the called procedure must ignore the reserved bits and access the count as an unsigned byte (for example, MOVZBL, TSTB, or CMPB).
The remaining longwords can be one of the following:
The standard permits programs to call by immediate value, by reference, by descriptor, or by combinations of these mechanisms. Interpretation of each argument list entry depends on agreement between the calling and called procedures. High-level languages use the reference or descriptor mechanisms for passing input parameters. OpenVMS system services and VAX BLISS, VAX C, DEC C, DEC C++, or VAX MACRO programs use all three mechanisms.
A procedure with no arguments is called with a list consisting of a 0 argument count longword, as follows:
CALLS #0, proc |
A missing or null argument---for example, CALL SUB(A,,B)---is represented by an argument list entry consisting of a longword 0. Some procedures allow trailing null arguments to be omitted and others require all arguments. See each procedure's specification for details.
The argument list must be treated as read-only data by the called
procedure and might be allocated in read-only memory at the option of
the calling program.
2.4.2 Argument Lists and High-Level Languages
Functional notations for procedure calls in high-level languages are mapped into VAX argument lists according to the following rules:
Because most high-level languages do not specify the order of evaluation of arguments (with respect to side effects), those language processors can evaluate arguments in any convenient order.
In constructing an argument list on the stack, a language processor can evaluate arguments from right to left and push their values on the stack. If call-by-reference semantics are used, argument expressions can be evaluated from left to right, with pointers to the expression values or descriptors being pushed from right to left.
The choice of argument evaluation order and code generation strategy is constrained only by the definition of the particular language. Do not write programs that depend on the order of evaluation of arguments. |
This calling standard permits arguments to be passed by immediate value, by reference, or by descriptor. By default, all language processors except VAX BLISS, VAX C, and VAX MACRO pass arguments by reference or by descriptor.
Language extensions are needed to reconcile the different argument-passing mechanisms. In addition to the default passing mechanism used, each language processor is required to give you explicit control, in the calling program, of the argument-passing mechanism for the data types supported by the language.
Table 2-2 lists various argument data-type groups. In the table, the value Yes means the language processor is responsible for providing the user with explicit control of that argument-passing mechanism group.
Data Type Group | Section | Value | Reference | Descriptor |
---|---|---|---|---|
Atomic <= 32 bits | 4.1 | Yes | Yes | Yes |
Atomic > 32 bits | 4.1 | No | Yes | Yes |
String | 4.2 | No | Yes | Yes |
Miscellaneous | 4.3 | No 1 | No | No |
Array | 5 | No | Yes | Yes |
For example, Digital Fortran provides the following intrinsic compile-time functions:
%VAL(arg) | By immediate value mechanism. Corresponding argument list entry is the value of the argument arg as defined in the language. |
%REF(arg) | By reference mechanism. Corresponding argument list entry contains the address of the value of the argument arg as defined in the language. |
%DESCR(arg) | By descriptor mechanism. Corresponding argument list entry contains the address of a descriptor of the argument arg as defined in Chapter 5 and in the language. |
Use these intrinsic functions in the syntax of a procedure call to control generation of the argument list. For example:
CALL SUB1(%VAL(123), %REF(X), %DESCR(A)) |
For more information, see the Digital Fortran language documentation.
In other languages, you can achieve the same effect by making appropriate attributes of the declaration of SUB1 in the calling program. Thus, you might write the following after making the external declaration for SUB1:
CALL SUB1 (123, X, A) |
A function value is returned in register R0 if its data type can be represented in 32 bits, or in registers R0 and R1 if its data type can be represented in 64 bits, provided the data type is not a string data type (see Section 4.2).
If the data type requires fewer than 32 bits, then R1 and the high-order bits of R0 are undefined. If the data type requires 32 or more bits but fewer than 64 bits, then the high-order bits of R1 are undefined. Two separate 32-bit entities cannot be returned in R0 and R1 because high-level languages cannot process them.
In all other cases (the function value needs more than 64 bits, the data type is a string, the size of the value can vary from call to call, and so on), the actual argument list and the formal argument list are shifted one entry. The new first entry is reserved for the function value. In this case, one of the following mechanisms is used to return the function value:
Some procedures, such as operating system calls and many library
procedures, return a success or failure value as a longword function
value in R0. Bit <0> of the value is set (Boolean true) for a
success and clear (Boolean false) for a failure. The particular success
or failure status is encoded in the remaining 31 bits, as described in
Section 6.1.
2.5.1 Returning a Function Value on Top of the Stack
If the maximum length of the function value is not known, the calling program can optionally allocate certain descriptors with the POINTER field set to 0, indicating that no space has been allocated for the value. If the called procedure finds POINTER 0, it fills in the POINTER, LENGTH, and other extent fields to describe the actual size and placement of the function value. This function value is copied to the top of the stack as control returns to the calling program.
This is an exception to the usual practice because the calling program regains control at the instruction following the CALLG or CALLS sequence with the contents of SP restored to a value different from the one it had at the beginning of its CALLG or CALLS calling sequence.
This technique applies only to the first argument in the argument list. Also, the called procedure cannot assume that the calling program expects the function value to be returned on the stack. Instead, the called procedure must check the CLASS field. If the descriptor is one that can be used to return a value on the stack, the called procedure checks the POINTER field. If POINTER is not 0, the called procedure returns the value using the semantics of the descriptor. If POINTER is 0, the called procedure fills in the POINTER and LENGTH fields and returns the value to the top of the stack.
Also, when POINTER is 0, the contents of R0 and R1 are unspecified by the called procedure. Once the called procedure fills in the POINTER field and other extent fields, the calling program may pass the descriptor as an argument to other procedures.
2.5.1.1 Returning a Fixed-Length or Varying String Function Value
If a called procedure can return its function value on the stack as a
fixed-length (see Section 5.2) or varying string (see Section 5.8),
the called procedure must also take the following actions (determined
by the CLASS and POINTER fields of the first descriptor in the argument
list):
CLASS | POINTER | Called Procedure's Action |
---|---|---|
S=1 | Not 0 | Copy the function value to the fixed-length area specified by the descriptor and space fill (hex 20 if ASCII) or truncate on the right. The entire area is always written according to Section 5.2. |
S=1 | 0 | Return the function value on top of the stack after filling in POINTER with the first address of the string and LENGTH with the length of the string to complete the descriptor according to Section 5.2. |
VS=11 | Not 0 | Copy the function value to the varying area specified by the descriptor and fill in CURLEN and BODY according to Section 5.8. |
VS=11 | 0 | Return the function value on top of the stack after filling in POINTER with the address of CURLEN and MAXSTRLEN with the length of the string in bytes (same value as contents of CURLEN) according to Section 5.8. |
Other | -- | Error. A condition is signaled. |
In both the fixed-length and varying string cases, the string is
unaligned. Specifically, the function value is allocated on top of the
stack with no unused bytes between the stack pointer value contained at
the beginning of the CALLS or CALLG sequence and the last byte of the
string.
2.6 Vector and Scalar Processor Synchronization
There are two kinds of synchronization between a scalar and vector processor pair: memory synchronization and exception synchronization.
Memory synchronization with the caller of a procedure that uses the vector processor is required because scalar machine writes (to main memory) might still be pending at the time of entry to the called procedure. The various forms of write-cache strategies allowed by the VAX architecture combined with the possibly independent scalar and vector memory access paths imply that a scalar store followed by a CALLx followed by a vector load is not safe without an intervening MSYNC.
Within a procedure that uses the vector processor, proper memory and exception synchronization might require use of an MSYNC instruction, a SYNC instruction, or both, prior to calling or upon being called by another procedure. Further, for calls to other procedures, the requirements can vary from call to call, depending on details of actual vector usage.
An MSYNC instruction (without a SYNC) at procedure entry, at procedure exit, and prior to a call provides proper synchronization in most cases. A SYNC instruction without an MSYNC prior to a CALLx (or RET) is sometimes appropriate. The remaining two cases, where both or neither MSYNC and SYNC are needed, are rare.
Refer to the VAX vector architecture section in the VAX MACRO and Instruction Set Reference Manual for
the specific rules on what exceptions are ensured to be reported by
MSYNC and other MFVP instructions.
2.6.1 Memory Synchronization
Every procedure is responsible for synchronization of memory operations with the calling procedure and with procedures it calls. If a procedure executes vector loads or stores, one of the following must occur:
Any procedure that executes vector loads or stores is responsible for synchronizing with potentially conflicting memory operations in any other procedure. However, execution of an MSYNC instruction to ensure scalar and vector memory synchronization can be omitted when it can be determined for the current procedure that all possibly incomplete vector load and stores operate only on memory not accessed by other procedures.
Previous | Next | Contents | Index |
privacy and legal statement | ||
5973PRO_001.HTML |