hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Programming Concepts Manual

HP OpenVMS Programming Concepts Manual


Previous Contents Index

18.2.3.4.2 Output Registers

Up to eight output registers are used for passing parameters. If a procedure call requires fewer than eight general registers for its parameters, the calling procedure does not need to allocate more than are needed. If the called procedure expects more parameters, it will allocate extra input registers; these registers will be uninitialized.

A procedure may also allocate more than eight registers in the output region. While the extra registers may not be used for passing parameters, they can be used as extra scratch registers. On a procedure call, they will show up in the called procedure's output area as excess registers, and may be modified by that procedure. The called procedure may also allocate few enough total registers in its stack frame that the top of the called procedure's frame is lower than the caller's top-of-frame, but those registers will become available again when control returns to the caller.

18.2.3.4.3 Rotating Registers

A subset of the registers in the procedure frame may be designated as rotating registers. The rotating register region always starts with R32, and may be any multiple of eight registers in number, up to a maximum of 96 rotating registers. The renaming is under control of the Register Rename Base (RRB).

If the rotating registers include any or all of the output registers, software must be careful when using the output registers for passing parameters, because a non-zero RRB will change the virtual register numbers that are part of the output region. In general, software should ensure either that the rotating region does not overlap the output region, or that the RRB is cleared to zero before setting output parameter registers.

18.2.3.4.4 Frame Markers

The current application-visible state of the register stack is stored in an architecturally inaccessible register called the current frame marker. On a procedure call, this register is automatically saved by copying it to an application register, the previous function state (AR.PFS). The current frame marker is modified to describe a new stack frame whose input and local area is initially zero size, and whose output area is equal in size to the previous output area. On return, the previous frame state register is used to restore the current frame marker to its earlier value, and the base of the register stack is adjusted accordingly.

It is the responsibility of a procedure to save the previous function state register before issuing any procedure calls of its own, and to restore it before returning.

18.2.3.4.5 Backing Store for Register Stack

When the depth of the procedure call stack exceeds the capacity of the physical register file, the hardware frees physical registers by saving them into a memory stack. This backing store is distinct from the memory stack described in Section 18.2.3.2.

As returns unwind the procedure call stack, the hardware also restores previously-saved physical registers from the backing store.

The operation of this register stack engine (RSE) is mostly transparent to application software. While the RSE is running, application software may not examine the contents of the backing store, and may not make any assumptions about how much of the register stack is still in physical registers or in the backing store. In order to examine previous stack frames, application software must synchronize the RSE with the FLUSHRS instruction. Synchronizing the RSE forces all stack frames up to, but not including, the current frame to be saved in backing store, allowing the software to examine the contents of the backing store without asynchronous operations modifying the memory. Modifications to the backing store require setting the RSE to enforced lazy mode after synchronizing it, which prevents the RSE from doing any operations other than those required by calls and returns. The procedure for synchronizing the RSE and setting the mode is described in the Intel® Itanium® Software Conventions and Runtime Architecture Guide.

The backing store grows towards higher addresses. The top of the stack, which corresponds to the top of the previous procedure frame, is available in the Backing Store Pointer (BSP) application register. The BSP must always point to a valid backing store address, because the operating system may need to start the RSE to process an exception.

Backing store overflow is automatically detected by the OpenVMS operating system, which will either extend the backing store to allow continued operation or will raise an exception. Unlike for the memory stack (see Section 18.2.3.2), there are no specific rules or requirements that must be satisfied to facilitate detection of backing store overflow.

A NaT collection register is stored into the backing store following each group of 63 physical registers. The NaT bit of each register stored is shifted into the collection register. When the BSP reaches the quadword just before a 64-quadword boundary, the RSE stores the collection register. Software can determine the position of the NaT collection registers in the backing store by examining the memory address. This process is described in greater detail in the Intel® Itanium® Architecture Software Developer's Manual.

18.3 Procedure Representation

A procedure value is an address value that represents a procedure.

On VAX systems, the procedure value is the address of the procedure entry mask that begins the actual code sequence of the procedure.

On Alpha systems, the procedure value in R27 is the address of the procedure descriptor that describes that procedure. So any OpenVMS Alpha procedure can be invoked by calling the stored address at offset 8 from the procedure descriptor (PDSC) starting address (procedure value).

For OpenVMS I64, a procedure value is the address of a function descriptor, which consists of at least two quadword fields: the address of the entry point and the GP value required by that procedure.

Every procedure whose address is taken, or might be taken, must have a unique official function descriptor. The address of this function descriptor is used for the procedure value that is passed as a parameter or when two procedure values are compared. For other purposes, additional local function descriptors may be used for efficiency (notably in images other than the image that contains the procedure).

An official function descriptor for any procedure which might be callable from a VAX or Alpha translated image must include signature information. A local function descriptor used to call a procedure that might be part of a VAX or Alpha translated image must also include additional fields to facilitate the call. Both of these cases are described in the HP OpenVMS Calling Standard.

A function descriptor for a bound procedure uses a special pseudo-GP value and includes an uplevel frame pointer. Such function descriptors are described in HP OpenVMS Calling Standard.

The several kinds of function descriptors are summarized in Table 18-8.

Table 18-8 Summary of Function Descriptor Kinds
Kinds and Roles Size (Quadwords)
Local function descriptor without translated image support 2
Local function descriptor with translated image support (jacket function descriptor) 4
Official function descriptor without translated image support 3
Official function descriptor with translated image support 3
Bound function descriptor 6

Note that the different kinds of function descriptor are not self-identifying (that is, they do not contain any form of tag or kind field).

18.4 Argument List

The calling standard defines a data structure called the argument list. An argument list is a sequence of locations in memory that represents a routine parameter list and possibly includes a function value. You use an argument list to pass information to a routine and receive results.

On VAX systems, the first longword in an argument list (see Figure 18-6) stores the number of arguments (the argument count, n) as an unsigned integer value. The maximum argument count is 255. The remaining 24 bits of the first longword are reserved for use by HP and must be 0.

Both integer and floating-point values can be an argument passed in the argument list. Note that a 64-bit floating-point argument counts as 2 longword arguments in the list.

Figure 18-6 Structure of a VAX Argument List


On Alpha systems, arguments are quadwords, and the calling program passes arguments in an argument item sequence. Each quadword in the sequence specifies a single argument. The argument item sequence is formed using R16--21 or F16--21 (a register for each argument). The argument item sequence can have a mix of integer and floating-point items that use both register types but must not repeat the same number. For example, an argument list might use R16, R17, F18, and R19. If there are more than six arguments, the argument items overflow to the end of the stack, as shown in Figure 18-7.

Figure 18-7 Alpha Argument List Format


The calling procedure must pass to the called procedure information about the argument list. For high-level languages, this is performed by the language processor. In the argument information (AI) register (R25), the quadword format is the structure shown in Figure 18-8. The AI register contains the argument count in the first byte. Table 18-9 describes the argument information fields in detail.

Figure 18-8 Argument Information (AI) Register (R25) Format


Table 18-9 Contents of the Argument Information (AI) Register (Alpha only)
Field Name Contents
AI$B_ARG_COUNT Unsigned byte <7:0> that specifies the number of 64-bit argument items in the argument list (known as the argument count).
AI$V_ARG_REG_INFO An 18-bit vector field <25:8> divided into 6 groups of 3 bits that correspond to the 6 arguments passed in registers. These groups describe how each of the first six arguments are passed in registers with the first group <10:8> describing the first argument. The encoding for each group for the argument register usage follows:
Value Name Meaning
0 AI$K_AR_I64 64-bit or 32-bit sign-extended to 64-bit argument passed in an integer register or

Argument is not present.

1 AI$K_AR_FF VAX F_floating argument passed in a floating register.
2 AI$K_AR_FD VAX D_floating argument passed in a floating register.
3 AI$K_AR_FG VAX G_floating argument passed in a floating register.
4 AI$K_AR_FS IEEE S_floating argument passed in a floating register.
5 AI$K_AR_FT IEEE T_floating argument passed in a floating register.
6, 7   Reserved.
Bits <63:26> Reserved and must be 0.

For I64, parameters are passed in a combination of general registers, floating-point registers, and memory, as illustrated in Figure 18-9.

The parameter list is formed by placing each individual parameter into fixed-size elements of the parameter list, referred to as parameter slots. Each parameter slot is 64 bits wide; parameters larger than 64 bits are placed in as many consecutive parameter slots as are needed to contain the entire parameter. The rules for allocation and alignment of parameter slots are described in Section 18.5.4.1.

The contents of the first eight parameter slots are always passed in registers, while the remaining parameters are always passed on the memory stack, beginning at the caller's stack pointer plus 16 bytes. The caller uses up to eight of the registers in the output region of its register stack for integer and VAX floating-point parameters, and up to eight floating-point registers for IEEE floating-point parameters. The maximum number of registers used is eight.

Figure 18-9 Parameter Passing in Registers and Memory


To accommodate variable argument lists in the C language, there is a fixed correspondence between parameter slots; the first parameter slot is always in either the first general output register or the first floating-point register (never both), the second parameter slot is always in the second general output register or the second floating-point register (never both), and so on. This allows a procedure to spill its register parameters easily to memory to form the argument home area before stepping through the parameter list with a pointer. The Argument Information register (AI) makes this possible, as explained in Section 18.5.6.

A procedure can assume that the NaT bits on its incoming general register arguments are clear, and that the incoming floating-point register arguments are not NaTVals. A procedure making a call must ensure only that registers containing actual parameters are clear of NaT bits or NaTVals; registers not used for actual parameters are undefined.

18.5 Argument Passing Mechanisms

Each high-level language supported by OpenVMS provides a mechanism for passing arguments to a procedure. The specifics of the mechanism and the terminology used, however, vary from one language to another. For specific information, refer to the appropriate high-level language user's guide.

OpenVMS system routines are external procedures that accept arguments. The argument list contains the parameters that are passed to the routine. Depending on the passing mechanisms for these parameters, the forms of the arguments contained in the argument list vary. As shown in Figures 18-10 and 18-11, argument entries labeled arg1 through argn are the actual parameters, which can be any of the following addresses or value:

Figure 18-10 Alpha Procedure Argument-Passing Mechanisms


Figure 18-11 VAX Procedure Argument-Passing Mechanisms


OpenVMS programming reference manuals provide a description of each OpenVMS system routine that indicates how each argument is to be passed. Phrases such as "an address" and "address of a character string descriptor" identify reference and descriptor arguments, respectively. Terms like "Boolean value," "number," "value," and "mask" indicate an argument that is passed by value.

18.5.1 Passing Arguments by Value

When your program passes an argument using the by value mechanism, the argument list entry contains either the actual uninterpreted 32-bit VAX value or a 64-bit Alpha or I64 value (zero- or sign-extended) of the argument. For example, to pass the constant 100 by value, the calling program puts 100 directly in the argument list or sequence. For more information about passing 64-bit Alpha and I64 values, refer to Chapter 11.

All high-level languages (except C) require you to specify the by-value mechanism explicitly when you call a procedure that accepts an argument by value. For example, FORTRAN uses the %VAL built-in function, while COBOL uses the BY VALUE qualifier on the CALL [USING] statement.

A FORTRAN program calls a procedure using the by-value mechanism as follows:


     INCLUDE  '($SSDEF)' 
     CALL LIB$STOP (%VAL(SS$_INTOVF)) 

A BLISS program calls this procedure as follows:


     LIB$SIGNAL (SS$_INTOVF) 

The equivalent VAX MACRO code is as follows:


     PUSHL    #SS$_INTOVF        ; Push longword by value 
     CALLS    #1,G^LIB$SIGNAL    ; Call LIB$SIGNAL 

A C language program calls a procedure using the by-value mechanism as follows:


 #include <starlet.h>         /* Declare the function*/ 
       . 
       . 
     enum  cluster0 
        { 
           completion, breakdown, beginning 
        }  event; 
 
     int status; 
     event = completion; 
       . 
       . 
     status = sys$setef(event);     /* Set event flag */ 

18.5.2 Passing Arguments by Reference

When your program passes arguments using the by reference mechanism, the argument list entry contains the address of the location that contains the value of the argument. For example, if variable x is allocated at location 1000, the argument list entry will contain 1000, the address of the value of x.

On Alpha processors and I64, the address is sign-extended from 32 bits to 64 bits.

Most languages (but not C) pass scalar data by reference by default. Therefore, if you simply specify x in the CALL statement or function invocation, the language automatically passes the value stored at the location allocated to x to the OpenVMS system routine.

A VAX BLISS program calls a procedure using the by-reference mechanism as follows:


    LIB$FLT_UNDER (%REF(1)) 

The equivalent VAX MACRO code is as follows:


ONE:     .LONG    1                     ; Longword value 1 
           . 
           . 
           . 
         PUSHAL    ONE                  ; Push address of longword 
         CALLS    #1,G^LIB$FLT_UNDER    ; Call LIB$FLT_UNDER 

A C language program calls a procedure using the by-reference mechanism as follows:


 
 /*  This program shows how to call system service SYS$READEF.  */ 
 
 #include <ssdef.h> 
 #include <stdio.h> 
 
 #include <starlet.h>        /* Declare the function */ 
 
 main(void) 
 { 
                               /*  Longword that receives the status * 
                                *  of the event flag cluster         */ 
   unsigned cluster_status; 
 
   int return_status;          /* Status: SYS$READEF       */ 
 
                               /*  Argument values for SYS$READEF  */ 
   enum  cluster0 
      { 
         completion, breakdown, beginning 
      }  event; 
      . 
      . 
      . 
   event = completion;           /*  Event flag in cluster 0 */ 
 
                                 /*  Obtain status of cluster 0.  * 
                                  *  Pass value of event and      * 
                                  *  address of cluster_status.   */ 
 
   return_status =  SYS$READEF(event, &cluster_status); 
 
                                   /*  Check for successful call  */ 
   if (return_status != SS$WASCLR && return_status != SS$WASSSET) 
      { 
         /* Handle the error here.                             */ 
            . 
            . 
            . 
      } 
   else 
      { 
         /*  Check bits of interest in cluster_status here.    */ 
            . 
            . 
            . 
      } 
  } 
 

18.5.3 Passing Arguments by Descriptor

When a procedure specifies that an argument is passed by descriptor, the argument list entry must contain the address of a descriptor for the argument. For more information about OpenVMS Alpha 64-bit descriptors, refer to Chapter 11.

On Alpha and I64 processors, the address is sign-extended from 32 bits to 64 bits.

This mechanism is used to pass more complicated data. For both Alpha and VAX systems, a descriptor includes at least the following fields:
Symbol Description
DSC$W_LENGTH Length of data (or DSC$W_MAXSTRLEN, maximum length, for varying strings)
DSC$B_DTYPE Data type
DSC$B_CLASS Descriptor class code
DSC$A_POINTER Address at which the data begins

The HP OpenVMS Calling Standard describes these fields in greater detail.

OpenVMS high-level languages include extensions for passing arguments by descriptor. When you specify by descriptor in these languages, the compiler creates the descriptor, defines its fields, and passes the address of the descriptor to the OpenVMS system routine. In some languages, by descriptor is the default passing mechanism for certain types of arguments, such as character strings. For example, the default mechanism for passing strings in BASIC is by descriptor.


    100    COMMON STRING GREETING = 30 
    200    CALL LIB$PUT_SCREEN(GREETING) 

The default mechanism for passing strings in COBOL, however, is by reference. Therefore, when passing a string argument to an OpenVMS system routine from a COBOL program, you must specify BY DESCRIPTOR for the string argument in the CALL statement.


    CALL LIB$PUT_OUTPUT USING BY DESCRIPTOR GREETING 

In VAX MACRO or BLISS, you must define the descriptor's fields explicitly and push its address onto the stack. Following is the VAX MACRO code that corresponds to the previous examples.


 
MSGDSC:    .WORD LEN                     ; DESCRIPTOR:  DSC$W_LENGTH 
           .BYTE DSC$K_DTYPE_T           ; DSC$B_DTYPE 
           .BYTE DSC$K_CLASS_S           ; DSC$B_CLASS 
           .ADDRESS MSG                  ; DSC$A_POINTER 
 
MSG:       .ASCII/Hello/                 ; String itself 
LEN = .-MSG                              ; Define the length of the string 
 
            .ENTRY  EX1,^M<> 
            PUSHAQ MSGDSC                ; Push address of descriptor 
            CALLS #1,G^LIB$PUT_OUTPUT    ; Output the string 
            RET 
            .END EX1 
 
 

The equivalent BLISS code looks like this:


MODULE BLISS1 (MAIN = BLISS1,      ! Example of calling LIB$PUT_OUTPUT 
        IDENT = '1-001', 
        ADDRESSING_MODE(EXTERNAL = GENERAL)) = 
BEGIN 
EXTERNAL ROUTINE 
    LIB$STOP,                   ! Stop execution via signaling 
    LIB$PUT_OUTPUT;             ! Put a line to SYS$OUTPUT 
 
FORWARD ROUTINE 
    BLISS1 : NOVALUE; 
 
LIBRARY 'SYS$LIBRARY:STARLET.L32'; 
 
ROUTINE BLISS1                  ! Routine 
        : NOVALUE = 
 
    BEGIN 
!+ 
! Allocate the necessary local storage. 
!- 
    LOCAL 
        STATUS,                         ! Return status 
        MSG_DESC : BLOCK [8, BYTE];     ! Message descriptor 
 
    BIND 
        MSG = UPLIT('HELLO'); 
 
!+ 
! Initialize the string descriptor. 
!- 
    MSG_DESC [DSC$B_CLASS] = DSC$K_CLASS_S; 
    MSG_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T; 
    MSG_DESC [DSC$W_LENGTH] = 5; 
    MSG_DESC [DSC$A_POINTER] = MSG; 
!+ 
! Put out the string.  Test the return status. 
! If it is not a success, then signal the RMS error. 
!- 
    STATUS = LIB$PUT_OUTPUT(MSG_DESC); 
    IF NOT .STATUS THEN LIB$STOP(.STATUS); 
    END;                ! End of routine BLISS1 
END                     ! End of module BLISS1 
ELUDOM 

A C language program calls a procedure using the by-descriptor mechanism as follows:


 /*  This program shows a call to system service SYS$SETPRN.    */ 
 
 #include <ssdef.h> 
 #include <stdio.h> 
                              /*  Define structures for descriptors */ 
 #include <descrip.h> 
 
 #include starlet.h            /*  Declare the function */ 
 
 int main(void) 
 { 
   int  ret;                  /*  Define return status of SYS$SETPRN  */ 
 
   struct  dsc$descriptor_s  name_desc;  /* Name the descriptor */ 
 
   char  *name =  "NEWPROC";             /* Define new process name */ 
      . 
      . 
      . 
   name_desc.dsc$w_length = strlen(name);  /* Length of name without * 
                                            * null terminator        */ 
 
   name_desc.dsc$a_pointer =  name; /* Put address of shortened string * 
                                     * in descriptor             */ 
 
   name_desc.dsc$b_class =  DSC$K_CLASS_S; /* String descriptor class */ 
 
   name_desc.dsc$b_dtype =  DSC$K_DTYPE_T; /* Data type: ASCII string */ 
      . 
      . 
      . 
   ret =  sys$setprn(&name_desc); 
 
   if (ret != SS$_NORMAL)          /*  Test return status      */ 
      fprintf(stderr, "Failed to set process name\n"), 
      exit(ret); 
      . 
      . 
      . 
 } 


Previous Next Contents Index