HP OpenVMS Systems Documentation

Content starts here

OpenVMS Programming Concepts Manual


Previous Contents Index

11.1.5 Sign-Extension Checking

OpenVMS system services not listed in Table 11-2 and all user-written system services that are not explicitly enhanced to accept 64-bit addresses will receive sign-extension checking. Any argument passed to these services that is not properly sign-extended will cause the error status SS$_ARG_GTR_32_BITS to be returned.

11.1.6 Language Support for 64-Bit System Services

C function prototypes for system services are available in SYS$LIBRARY:SYS$STARLET_C.TLB (or STARLET).

No 64-bit MACRO-32 macros are available for system services. The MACRO-32 caller must use the AMACRO built-in EVAX_CALLG_64 or the $CALL64 macro. For more information about MACRO-32 programming support for 64-bit addressing, see OpenVMS MACRO-32 Porting and User's Guide.

11.1.7 NEW STARLET Definitions for C

As of OpenVMS Alpha Version 7.0, SYS$LIBRARY:SYS$STARLET_C.TLB (or STARLET) provides C function prototypes for system services, as well as new and enhanced data structure definitions. The new definitions are more consistent with the OpenVMS C language coding conventions and definitions (typedefs) used in SYS$LIBRARY:SYS$LIB_C.TLB.

To maintain source compatibility for existing users of STARLET.H, the old style function declarations and definitions are still provided by default. To take advantage of the new system service function prototypes and type definitions, you must explicitly enable them.

You can either define the __NEW_STARLET symbol with a Compaq C command line qualifier or include the definition directly in your source program. For example:

  • Define the _NEW_STARLET symbol with the Compaq C command line qualifier as follows:


     /DEFINE=(__NEW_STARLET=1)
    

    or
  • Define the __NEW_STARLET symbol in your C source program before including the SYS$STARLET_C.TLB header files:


    #define __NEW_STARLET 1
    
    #include  <starlet.h>
    #include  <vadef.h>
    

To see the currently available system service function prototypes in STARLET.H, you can use the Librarian Utility, as shown in the following example:


$ LIBRARY/OUTPUT=STARLET.H SYS$LIBRARY:SYS$STARLET_C.TLB/EXTRACT=STARLET

The following example shows a new system service function prototype as it is defined in STARLET.H:


    #pragma __required_pointer_size __long

     int sys$expreg_64(
               struct _generic_64 *region_id_64,
               unsigned __int64 length_64,
               unsigned int acmode,
               unsigned int flags,
               void *(*(return_va_64)),
               unsigned __int64 *return_length_64);

    #pragma __required_pointer_size __short

For more information about Compaq C pointer size pragmas, see the DEC C User's Guide for OpenVMS Systems.

The following source code example shows the sys$expreg_64 function prototype referenced in a program.



#define __NEW_STARLET 1               /* Enable "New Starlet" features */

#include <starlet.h>                  /* Declare prototypes for system services */
#include <gen64def.h>                 /* Define GENERIC_64 type */
#include <vadef.h>                    /* Define VA$ constants */

#include <ints.h>                     /* Define 64-bit integer types */
#include <far_pointers.h>             /* Define 64-bit pointer types */

{
    int status;                       /* Ubiquitous VMS status value */
    GENERIC_64 region = { VA$C_P2 };  /* Expand in "default" P2 region */
    VOID_PQ p2_va;                    /* Returned VA in P2 space */
    uint64 length;                    /* Allocated size in bytes */
    extern uint64 page_size;          /* Page size in bytes */

    status = sys$expreg_64( &region, request_size, 0, 0, &p2_va, &length );
    ...

}

Table 11-3 lists the data structures that are used by the new function prototypes.

Table 11-3 Structures Used by_NEW_STARLET Prototypes
Structure Used by Prototype Defined by Header File Common Prefix for Structure Member Names Description
struct _cluevthndl cluevtdef.h cluevthndl$ Cluster event handle
struct _fabdef fabdef.h fab$ File access block
struct _generic_64 gen64def.h gen64$ Generic quadword structure
struct _ieee ieeedef.h ieee$ IEEE floating point control structure
struct _ile2 1 iledef.h ile2$ Item list entry 2
struct _ile3 1 iledef.h ile3$ Item list entry 3
struct _ilea_64 1 ilea_64$ iledef.h 64-bit item list entry A structure
struct _ileb_64 1 ileb_64$ iledef.h 64-bit item list entry B structure
struct _iosa iosadef.h iosa$ I/O status area
struct _iosb iosbdef.h iosb$ I/O status block
struct _lksb lksbdef.h lksb$ Lock status block
struct _rabdef rabdef.h rab$ RMS record access block
struct _secid seciddef.h secid$ Global section identifier
struct _va_range va_rangedef.h va_range$ 32-bit virtual address range

1Use of this structure type is not required by the function prototypes in starlet.h. This structure type is provided as a convenience and can be used where it is appropriate.

11.2 RMS Interface Enhancements for 64-Bit Addressing

This section summarizes changes to the RMS interface that support 64-bit addressing and enable you to use RMS to perform input and output operations to P2 or S2 space. You can take full advantage of these RMS enhancements by making only minor modifications to existing RMS code.

For complete information about RMS support for 64-bit addressing, see the OpenVMS Record Management Services Reference Manual.

The RMS user interface consists of a number of control data structures (FAB, RAB, NAM, XABs). These are linked together with 32-bit pointers and contain embedded pointers to I/O buffers and various user data buffers, including file name strings and item lists. RMS support for 64-bit addressable regions allows 64-bit addresses for the following user I/O buffers:

  • UBF (user record buffer)
  • RBF (record buffer)
  • RHB (fixed-length record header buffer; fixed portion of VFC record format)
  • KBF (key buffer containing the key value for random access)

The prompt buffer pointed to by RAB$L_PBF is excluded because the terminal driver does not allow 64-bit addresses.

Specific enhancements to the RMS interface for 64-bit addressing are as follows:

  • Data buffers can be placed in P2 or S2 space for the following user I/O services:
    • Record I/O services: $GET, $FIND, $PUT, $UPDATE
    • Block I/O services: $READ, $WRITE
  • The RAB structure points to the record and data buffers used by these services.
  • An extension of the existing RAB structure is used to specify 64-bit buffer pointers and sizes.
  • The buffer size maximum for RMS block I/O services ($READ and $WRITE) has been increased from 64 KB to 2 GB, with two exceptions:
    • For RMS journaling, a journaled $WRITE service is restricted to the current maximum (65535 minus 99 bytes of journaling overhead). An RSZ error is returned to RAB$L_STS if the maximum is exceeded.
    • Magnetic tape is still limited to 65535 bytes at the device driver level.

    Buffer size maximums for RMS record I/O services ($GET, $PUT, $UPDATE) have not changed. Prior RMS on-disk record size limits still apply.

The rest of the RMS interface currently is restricted to 32-bit pointers:

  • FAB, RAB, NAM, and XABs must still be allocated in 32-bit space.
  • Any descriptors or embedded pointers to file names, item lists, and so on, must continue to use 32-bit pointers.
  • Any arguments passed to the RMS system services remain 32-bit arguments. If you attempt to pass a 64-bit argument, the SS$_ARG_GTR_32_BITS error is returned.

11.2.1 RAB64 Data Structure

The RAB64, a RMS user interface structure, is an extended RAB that can accommodate 64-bit buffer addresses. The RAB64 data structure consists of a 32-bit RAB structure followed by a 64-bit extension as shown below:


The RAB64 contains fields identical to all of the RAB fields except that field names have the RAB64 prefix instead of the RAB prefix. In addition, RAB64 has the following fields in the extension:

This field... Is an extension
of this field
Description
RAB64$Q_CTX RAB64$L_CTX User context. This field is not used by RMS but is available to the user. The CTX field is often used to contain a pointer. For asynchronous I/O, it provides the user with the equivalent of an AST parameter.
RAB64$PQ_KBF RAB64$L_KBF Key buffer address containing the key value for random access (for $GET and $FIND).
RAB64$PQ_RBF RAB64$L_RBF Record buffer address (for $PUT, $UPDATE, and $WRITE).
RAB64$PQ_RHB RAB64$L_RHB Record header buffer address (fixed portion of VFC record format).
RAB64$Q_RSZ RAB64$W_RSZ Record buffer size.
RAB64$PQ_UBF RAB64$L_UBF User buffer address (for $GET and $READ).
RAB64$Q_USZ RAB64$W_USZ User buffer size.

Note that the fields with the PQ tag in their names can hold either a 64-bit address or a 32-bit address sign-extended to 64 bits. Therefore, you can use the fields in all applications whether or not you are using 64-bit addresses.

For most record I/O service requests, there is an RMS internal buffer between the device and the user's data buffer. The one exception occurs with the RMS service $PUT. If the device is a unit record device and it is not being accessed over the network, RMS passes the address of the user record buffer (RBF) to the $QIO system service. If you inappropriately specify a record buffer (RBF) allocated in 64-bit address space for a $PUT to a unit record device that does not support 64-bit address space (for example, a terminal), the $QIO service returns SS$_NOT64DEVFUNC. (See Writing OpenVMS Alpha Device Drivers in C and OpenVMS Alpha Guide to Upgrading Privileged-Code Applications for more information about $QIO.) RMS returns the error status RMS$_SYS with SS$_NOT64DEVFUNC as the secondary status value in RAB64$L_STV.

RMS system services support the RAB structure as well as the RAB64 structure.

11.2.2 Using the 64-Bit RAB Extension

Only minimal source code changes are required for applications to use 64-bit RMS support.

RMS allows you to use the RAB64 wherever you can use a RAB. For example, you can use RAB64 in place of a RAB as the first argument passed to any of the RMS record or block I/O services.

Because the RAB64 is an upwardly compatible extension of the existing RAB, most source modules can treat references to fields in a RAB64 as if they were references to a RAB. The 64-bit buffer address counterpart is used by the source module only if the following two conditions are met:

  • The RAB64$B_BLN field has been initialized to RAB64$C_BLN64 to show that the extension is present.
  • The 32-bit address field in the 32-bit portion of the RAB contains -1 .

The source module uses the value in the quadword size field only if the contents of the 32-bit address field designate its use. For example:

If this address field contains -1 The address in this
field is used
And the size in this
field is used
RAB64$L_UBF RAB64$PQ_UBF 1 RAB64$Q_USZ
RAB64$L_RBF RAB64$PQ_RBF 1 RAB64$Q_RSZ
RAB64$L_KBF RAB64$PQ_KBF RAB64$B_KSZ
RAB64$L_RHB RAB64$PQ_RHB FAB$B_FSZ

1This field can contain either a 64-bit address or a 32-bit address sign-extended to 64 bits.

While RMS allows you to use the RAB64 wherever you can use a RAB, some source languages may impose other restrictions. Consult the documentation for your source language for more information.

11.2.3 Macros to Support User RAB Structure

The following new MACRO-32 and BLISS macros have been implemented to support the 64-bit extension to the user RAB structure:

  • MACRO-32 macros
    • $RAB64 (counterpart to $RAB)
    • $RAB64_STORE (counterpart to $RAB_STORE)

    Using these macros has the following results:
    • RAB$B_BLN is assigned the constant of RAB$C_BLN64.
    • The original longword I/O buffers are initialized to -1 , and the USZ and RSZ word sizes are initialized to 0.
    • Values specified using the UBF, USZ, RBF, RSZ, RHB, or KBF keywords are moved into the quadword fields for these keywords. (In contrast, the $RAB and $RAB_STORE macros move these values into the longword [or word] fields for these keywords.)
  • BLISS macros
    The following BLISS macros are available only in the STARLET.R64 library because they use the QUAD keyword, which is available only to BLISS-64. Thus, any BLISS routines referencing them must be compiled using the BLISS-64 compiler.
    • $RAB64 (counterpart to $RAB)
    • $RAB64_INIT (counterpart to $RAB_INIT)
    • $RAB64_DECL (counterpart to $RAB_DECL)

    Using the first two macros has these results:
    • RAB$B_BLN is assigned the constant of RAB$C_BLN64.
    • The original longword I/O buffers are initialized to -1 , and the USZ and RSZ word sizes are initialized to 0.
    • Values assigned to the keywords UBF, USZ, RBF, RSZ, RHB, or KBF are moved into the quadword fields for these keywords. (In contrast, the $RAB and $RAB_INIT macros move these values into the longword [or word] fields for these keywords.)

    The third macro allocates a block structure of bytes with a length of RAB$C_BLN64.

11.3 File System Support for 64-Bit Addressing

The Extended QIO Processor (XQP) file system, which implements the Files-11 On-Disk Structure Level 2 (ODS-2) and the Magnetic Tape Ancillary Control Process both provide support for the use of 64-bit buffer addresses for virtual read and write functions.

The XQP and ACP translate a virtual I/O request to a file into one or more logical I/O requests to a device. Because the buffer specified with the XQP or ACP request is passed on to the device driver, the support for buffers in P2 or S2 space is also dependent on the device driver used by the XQP and ACP.

All OpenVMS supplied disk and tape drivers support 64-bit addresses for data transfers to and from disk and tape devices on the virtual, logical, and physical read and write functions. Therefore, the XQP and Magnetic Tape ACP support buffers in P2 or S2 space on the virtual read and write functions.

The XQP and ACP do not support buffer addresses in P2 or S2 space on the control functions (IO$_ACCESS, IO$_DELETE, IO$_MODIFY, and so on).

For more information about device drivers that support 64-bit buffer addresses, see Writing OpenVMS Alpha Device Drivers in C.

11.4 OpenVMS Alpha 64-Bit API Guidelines

This section describes the guidelines used to develop 64-bit interfaces to support OpenVMS Alpha 64-bit virtual addressing. Application programmers who are developing their own 64-bit application programming interfaces (APIs) might find this information useful.

These recommendations are not hard and fast rules. Most are examples of good programming practices.

For more information about C pointer pragmas, see the DEC C User's Guide for OpenVMS Systems.

11.4.1 Quadword/Longword Argument Pointer Guidelines

Because OpenVMS Alpha 64-bit adressing support allows application programs to access data in 64-bit address spaces, pointers that are not 32-bit sign-extended values (64-bit pointers) will become more common within applications. Existing 32-bit APIs will continue to be supported, and the existence of 64-bit pointers creates some potential pitfalls that programmers must be aware of.

For example, 64-bit addresses may be inadvertently passed to a routine that can handle only a 32-bit address. Another dimension of this would be a new API that includes 64-bit pointers embedded in data structures. Such pointers might be restricted to point to 32-bit address spaces initially, residing within the new data structure as a sign-extended 32-bit value.

Routines should guard against programming errors where 64-bit addresses are being passed instead of 32-bit addresses. This type of checking is called sign-extension checking, which means that the address is checked to ensure that the upper 32 bits are all zeros or all ones, matching the value of bit 31. This checking can be performed at the routine interface that is imposing this restriction.

When defining a new routine interface, you should consider the ease of programming a call to the routine from a 32-bit source module. You should also consider calls written in all OpenVMS programming languages, not just those languages initially supporting 64-bit addressing. To avoid promoting awkward programming practices for the 32-bit caller of a new routine, you should accommodate 32-bit callers as well as 64-bit callers.

Arguments passed by reference that are restricted to reside in a 32-bit address space (P0/P1/S0/S1) should have their reference addresses sign-extension checked.

The OpenVMS Calling Standard requires that 32-bit values passed to a routine be sign-extended to 64-bits before the routine is called. Therefore, the called routine always receives 64-bit values. A 32-bit routine cannot tell if its caller correctly called the routine with a 32-bit address, unless the reference to the argument is checked for sign-extension.

This sign-extension checking would also apply to the reference to a descriptor when data is being passed to a routine by descriptor.

The called routine should return the error status SS$_ARG_GTR_32_BITS if the sign-extension check fails.

Alternately, if you want the called routine to accept the data being passed in a 64-bit location without error and if the sign-extension check fails, the data can be copied by the called routine to a 32-bit address space. The 32-bit address space to which the routine copies the data can be local routine storage (that is, the current stack). If the data is copied to a 32-bit location other than local storage, memory leaks and reentrancy issues must be considered.

When new routines are developed, pointers to code and all data pointers passed to the new routines should be accommodated in 64-bit address spaces where possible. This is desirable even if the data is a routine or is typically considered static data, which the programmer, compiler, or linker would not normally put in a 64-bit address space. When code and static data is supported in 64-bit address spaces, this routine should not need additional changes.

32-bit descriptor arguments should be validated to be 32-bit descriptors.

Routines that accept descriptors should test the fields that allow you to distinguish the 32-bit and 64-bit descriptor forms. If a 64-bit descriptor is received, the routine should return an error.

Most existing 32-bit routines will return or signal the error status SS$_ACCVIO when incorrectly presented with a 64-bit descriptor for the following reasons:

  • The 64-bit form of a descriptor contains an MBO (must be one) word at offset 0, where the 32-bit descriptor LENGTH is located, and
  • An MBMO (must be minus one) longword at offset 4, where the 32-bit descriptor's POINTER is located, as shown in the following figure:

Routines that accept arguments passed by 64-bit descriptors should accommodate 32-bit descriptors as well as 64-bit descriptors.

New routines should accommodate 32-bit and 64-bit descriptors within the same routine. The same argument can point to either a 32-bit or 64-bit descriptor. The 64-bit descriptor MBO word at offset 0 should be tested for 1, and the 64-bit descriptor MBMO longword at offset 4 should be tested for a -1 to distinguish between a 64-bit and 32-bit descriptor.

Consider an existing 32-bit routine that is being converted to handle 64-bit as well as 32-bit descriptors. If the input descriptor is determined to be a 64-bit descriptor, the data being pointed to by the 64-bit descriptor can first be copied to a 32-bit memory location, then a 32-bit descriptor would be created in 32-bit memory. This new 32-bit descriptor can then be passed to the existing 32-bit code, so that no further modifications need to be made internally to the routine.

32-bit item list arguments should be validated to be 32-bit item lists.

Two forms of item lists are defined: item_list_2 and item_list_3. The item_list_2 form of an item list consists of two longwords with the first longword containing a length and item code fields, while the second longword typically contains a buffer address.

The item_list_3 form of an item list consists of three longwords with the first longword containing a length and item code fields, while the second and third longwords typically contain a buffer address and a return length address field.

Since two forms of 32-bit item lists exist, two forms of a 64-bit item list are defined. Dubbed item_list_64a and item_list_64b, these item list forms parallel their 32-bit counterparts. Both forms of item list contain the MBO and MBMO fields at offsets 0 and 4 respectively. They also each contain a word-sized item code field, a quadword-sized length field, and a quadword-sized buffer address field. The item_list_64b form of an item list contains an additional quadword for the return length address field. The returned length is 64-bits.

Routines that accept item lists should test the fields that allow you to distinguish the 32-bit and 64-bit item list forms. If a 64-bit item list is received, the routine should return an error.

Most existing 32-bit routines will return or signal the error status SS$_ACCVIO when incorrectly presented with a 64-bit item list for the following reasons:

  • The 64-bit form of an item list contains an MBO (must be one) word at offset 0, where the 32-bit item list LENGTH is located, and
  • An MBMO (must be minus one) longword at offset 4, where the 32-bit item list's BUFFER ADDRESS is located as shown in Figure 11-7 and Figure 11-8.

Figure 11-7 item_list_64a


Figure 11-8 item_list_64b


Routines that accept arguments passed by 64-bit item list arguments should accommodate 32-bit item lists as well as 64-bit item lists.

New routines should accommodate 32-bit and 64-bit item lists within the same routine. The same argument can point to either a 32-bit or 64-bit item list. The 64-bit item list MBO word at offset 0 should be tested for 1, and the 64-bit item list MBMO longword at offset 4 should be tested for a -1 to distinguish between a 64-bit and 32-bit item list.

Avoid passing pointers by reference.

If passing a pointer by reference is necessary, as with certain memory management routines, the pointer should be defined to be 64-bit wide.

Mixing 32-bit and 64-bit pointers can cause programming errors when the caller incorrectly passes a 32-bit wide pointer by reference when a 64-bit wide pointer is expected.

If the called routine reads a 64-bit wide pointer that was allocated only one longword by the programmer, the wrong address could be used by the routine.

If the called routine returns a 64-bit pointer, and therefore writes a 64-bit wide address into a longword allocated by the programmer, data corruption can occur.

Existing routines that are passed pointers by reference require new interfaces for 64-bit support. Old routine interfaces would still be passed the pointer in a 32-bit wide memory location and the new routine interface would require that the pointer be passed in a 64-bit wide memory location. Keeping the same interface and passing it 64-bit wide pointers would break existing programs.

Example: The return virtual address used in the SYS$CRETVA_64 service is an example of when it is acceptable to pass a pointer by reference. Virtual addresses created in P0 and P1 space are guaranteed to have only 32 bits of significance, however all 64 bits are returned. SYS$CRETVA_64 can also create address space in 64-bit space and thus return a 64-bit address. The value that is returned must always be 64 bits because a 64-bit address can be returned.

Memory allocation routines should return the pointer to the data allocated by value (that is, in R0), if possible. The C allocation routines, malloc, calloc, and realloc are examples of this.

New interfaces for routines that are not memory management routines should avoid defining output arguments to receive addresses. Problems will arise whenever a 64-bit subsystem allocates memory and then returns a pointer back to a 32-bit caller in an output argument. The caller may not be able to support or express a 64-bit pointer. Instead of returning a pointer to some data, the caller should provide a pointer to a buffer and the called routine should copy the data into the user's buffer.


Previous Next Contents Index