HP OpenVMS Systems Documentation

Content starts here

OpenVMS MACRO-32 Porting and User's Guide

Previous Contents Index

1.4 Identifying Nonportable VAX MACRO Coding Practices

When examining a VAX MACRO module that you intend to compile to OpenVMS Alpha object code, look for any of the following coding constructs. The occurrence of these in a module can make porting take longer than it would otherwise. Although the compiler can identify many of these practices, recognizing them yourself will speed up the porting effort. For more information about nonportable MACRO coding practices, including some that occur less frequently and are less easy to detect, see Chapter 3.

  1. Removing the return address from the stack to return to the caller's caller, such as the following (see Section 3.3.4):

    TSTL    (SP)+               ; remove return address
    RSB                         ; return to caller's caller
  2. Temporarily removing the return address from the stack to allocate space on the stack using mechanisms such as the following (see Section 3.3.4):

    POPL    R0                  ; remove the return address
    SUBL    #structure_size,SP  ; allocate stack space for caller
    PUSHL   R0                  ; replace the return address

    POPL    R1                  ; hold return address
    PUSHL   structure           ; build structure for caller
    ; code continues
    JMP     (R1)                ; return to caller
  3. Pushing a label onto the stack, as in the following examples, often as an attempt to construct a return address for an RSB instruction (see Section 3.3.3):

    MOVAL   routine_label,-(SP)

    PUSHAL  routine_label

  4. Modifying the frame pointer (FP) (see Section 3.1.1). VAX MACRO code typically modifies the frame pointer for one of two reasons:
    • To manually assemble a call frame on the stack.
    • To use the frame pointer to reference local storage allocated in a .JSB_ENTRY routine.

    MOVL    SP,FP
    SUBL    #data_area,SP
  5. Constructing an REI target, as in the following examples (see Section 3.3.7):

    MOVL    #fake_psl,-(SP)
    MOVAL   target_label,-(SP)      ; all three

    MOVPSL  -(SP)
    MOVAL   target_label,-(SP)      ; force AST delivery only

            MOVL    #fake_psl,-(SP)
            BSBW    DOREI
            ; code continues
  6. Branching to a destination that consists of a label plus an offset as in the following example. The appearance of this practice in VAX MACRO code may indicate a branch past some data in the code stream, such as the register save mask at the top of a .CALL_ENTRY routine (see Section 3.2.1). Alternatively, it may be a sign that the code is familiar with and dependent upon the size of VAX instructions (see Section 3.2.3).

    BRx     label+offset
  7. Moving an opcode to a location, usually the stack or a data area, as shown in the following example. This practice indicates either generated or self-modifying code and will require redesign as indicated in Section 3.2.2.

    MOVB    #OP$_opcode,(Rx)

    MOVZBL  #OP$_opcode,(Rx)
  8. Jumping across modules. Because of architectural requirements, the compiler must handle jumps across modules as JSBs. Therefore, external branch targets as in the following example must be declared with the .JSB_ENTRY directive (see Section 2.2.3).

    JMP     G^external_routine

1.5 Establishing Useful Coding Conventions

Section 1.3 describes a recommended process for porting VAX MACRO code to OpenVMS Alpha. Although this process may provide a mechanism for porting code efficiently, it cannot by itself guarantee that the porting effort will be consistent among the engineers who are performing the porting, or will be intelligible to the engineers who will later need to debug and test ported code. To ensure that the porting effort proceeds uniformly and that its effects on source code are well documented, an engineering group should establish coding conventions that are relevant to the goals of the effort.

Naturally, any methodology an engineering group may adopt should be shaped by that group's development environment, including those procedures the group follows for tool management, source code control, common code, and testing. The coding conventions an engineering group should evaluate include:

  • Establishing VAX MACRO source modules that are common to VAX and Alpha systems, and conditionalizing architecture specific code (see Section 1.6)
  • Providing clear and consistent register declarations in the compiler's entry-point directives (see Section 2.2)

1.6 Maintaining Common Sources for VAX and Alpha Systems

When designing a VAX MACRO code porting effort, consider the benefits of maintaining common sources for VAX and Alpha systems. It is advantageous to an engineering group to have only one copy of its sources to maintain and enhance, and common sources help ensure common user interfaces. However, if you find that you are conditionalizing so much source code that it is no longer intelligible, take steps to restructure the code into architecture-specific and architecture-independent pieces. If the number of these pieces becomes unmanageable, create separate architecture-specific modules.

1.6.1 Including Compiler Directive Definitions

A successful compilation does not preclude VAX MACRO code in a source file from also processing successfully under the VAX MACRO assembler. If you added any compiler directives to your code, they will be resolved by the library SYS$LIBRARY:STARLET.MLB when the code is assembled. The assembler automatically searches this library for any undefined macros. After finding these definitions, the assembler will ignore occurrences of the compiler directives.

However, if you are using OpenVMS VAX Version 6.0 or earlier, you must first extract the directive definitions from ALPHA$LIBRARY:STARLET.MLB on Alpha and insert them into your SYS$LIBRARY:STARLET.MLB on OpenVMS VAX. For example:


Note that many of the definitions of the compiler directives refer to other macros. Make sure to extract not only the definitions of all the compiler directives used in your code but also all the associated macros and insert them into SYS$LIBRARY:STARLET.MLB on your OpenVMS VAX system.

1.6.2 Removing VAX Dependencies

If you must make changes to source files because they contain certain coding practices that cannot be directly compiled into Alpha code, you may still be able to generate images for both VAX and Alpha systems from common VAX MACRO sources.

Removing such VAX dependencies so that the same code can run on both VAX and Alpha systems can yield great benefits during the porting process. You can debug single modules or groups of modules of the ported code by building and testing the modules in the VAX environment. This can greatly speed your debugging process.

In some cases, you must define and implement procedures for conditionalizing the source files (as described in Section 1.6.3) or for providing separate sources for VAX and Alpha systems.

If the code runs in an inner mode, it is unlikely that an effort to generate VAX and Alpha images from common VAX MACRO sources will be fully successful. Because inner-mode code interoperates with the executive, it is vulnerable to the differences between VAX and Alpha system interfaces and executive data structures. However, user-mode code is generally immune from architectural dependencies and may more easily serve as the basis for common code.

1.6.3 Using Architecture-Specific Symbols

Conditionalizing VAX MACRO code requires the use of two ARCH_DEFS.MAR files with architecture-specific symbols, one to be assembled with the VAX MACRO source code on a VAX processor, the other to be compiled with the VAX MACRO source code on an Alpha processor.

If you choose to make code in a common source module conditional on architecture type, include ARCH_DEFS.MAR in your assembly and compilation and use .IF DF,VAX or .IF DF,ALPHA.

An ARCH_DEFS.MAR file is provided with OpenVMS Alpha. You need to create a corresponding file for OpenVMS VAX. The following is an example of such a file:

; This is the VAX version of ARCH_DEFS.MAR, which contains
; architectural definitions for compiling sources for
; VAX systems.
VAX = 1

The Alpha version exists in SYS$LIBRARY and contains definitions for the following symbols:

  • ALPHA---to indicate the source code is Alpha architecture specific
  • BIGPAGE---to indicate the source code assumes variable memory page size


Any other symbols in ARCH_DEFS.MAR on OpenVMS Alpha are specific to OpenVMS Alpha source code and are not guaranteed to be included from release to release.

1.7 Using the MACRO-32 Compiler

Compaq recommends that you use the current version of the MACRO-32 compiler. Make sure that the version of SYS$LIBRARY:STARLET.MLB that ships with the compiler version you are using is installed on your system and that the logical name points to the correct directory.

For compiling code to run on AlphaServer systems with the Alpha processor 21264 (or later), you must use the following version of the MACRO-32 compiler:

  • Version 3.1 or later for OpenVMS Alpha Version 7.1-2
  • Version 4.1 or later for OpenVMS Alpha Version 7.2
  • Shipping version of the compiler for later versions of OpenVMS Alpha

Directions for invoking the compiler are provided in Appendix A.

Chapter 2
How to Use the MACRO-32 Compiler

The MACRO-32 Compiler for OpenVMS Alpha has been designed to help you port VAX MACRO source code from OpenVMS VAX to OpenVMS Alpha. When operating on VAX MACRO code that complies with the restrictions and guidelines described in this manual, the compiler produces a valid OpenVMS Alpha object module that preserves the semantics of the original VAX MACRO source and adheres to the OpenVMS calling standard.

This chapter describes the following topics:

As discussed in Chapter 1, the compiler cannot transparently convert all VAX MACRO code. There are many coding practices that cannot be directly compiled into OpenVMS Alpha code. They must be removed or modified to guarantee a successful compilation. The compiler can detect and report many of these coding practices.

2.1 Using Alpha Registers

Alpha computers employ 32 integer registers, R0 through R31. Because code generated by the compiler uses Alpha registers R0 through R12 as if they were VAX registers, VAX MACRO code usage of these registers (for instance, as input to JSB routines) does not have to change to achieve a correct compilation. VAX MACRO instructions (such as MOVL and ADDL) use the lower 32 bits of the Alpha register involved in the operation. The compiler maintains a sign-extended 64-bit form of this value in the register.

Registers R13 and above are also available to VAX MACRO code that will be compiled to OpenVMS Alpha object format. If you decide to use these registers, review the following constraints:

  • Generally, existing VAX MACRO code uses only registers R0 through R11, R12 through R14 being specially defined as the argument pointer (AP), frame pointer (FP), and stack pointer (SP), respectively. The compiler will compile legal uses of AP, FP, and SP as references to the Alpha registers that have functions similar to the VAX registers. If a VAX MACRO source is referencing AP as a scratch register, the compiler converts this reference to a reference to R12. If this is not desirable, you should change the code to use a different scratch register.
  • If the compiler detects a reference to R12, R13, and R14 in a VAX MACRO source, it will not convert it to a reference to the Alpha equivalent of AP, FP, or SP. Rather, it will consider the reference to be to the corresponding Alpha integer register.
  • Code that uses R13 and above cannot be assembled by the VAX MACRO assembler. Therefore, it should be conditionalized for OpenVMS Alpha or appear in a module that is specific to OpenVMS Alpha.
  • The compiler allows you to access the full 64 bits of Alpha registers by using the EVAX_LDQ and EVAX_STQ built-ins, as described in Appendix C.
  • You should take special care when referencing registers with specific architected usage, as defined in the OpenVMS Calling Standard.
  • Registers 16 and above are scratch registers, as defined in the OpenVMS Calling Standard. You cannot expect their values to survive across routine calls.
  • The compiler may use registers R13 and above as temporary registers if they are not used in the source code for a routine. R13 through R15 are saved and restored if they are used.

2.2 Routine Calls and Declarations

The OpenVMS Calling Standard specifies very different calling conventions for VAX and Alpha systems.

On a VAX system, there are two different call formats, CALL and JSB, with five different instructions: CALLS, CALLG, JSB, BSBW, and BSBB. CALL instructions create a frame on the stack which contains return information, saved registers, and other routine information. Parameters to CALL instructions are passed in consecutive longword memory locations, either on the stack (CALLS) or elsewhere (CALLG). JSB instructions have the return address stored on the stack. For both call formats, the hardware processing of the calling instruction provides all of these functions.

On an Alpha system, there is only one call format and only one subroutine call instruction, JSR. For routines that expect parameters, the first six parameters are passed in R16 through R21, with the parameter count in R25 and subsequent parameters in quadwords on the stack. The hardware execution of the JSR instruction simply passes control to the subroutine and places the return address in a designated register. It neither allocates stack space, nor creates a call frame, nor provides any parameter manipulations. All of these functions must be done by the calling routine or the called routine.

The compiler must generate code that conforms to the OpenVMS Calling Standard yet emulates the function of the different VAX MACRO instructions. This requires special code both at the calling instruction to manipulate the input parameters and at the entry point of the routine itself to create a stack frame and other context.

The compiler generates code only for source instructions that are part of a declared routine. For the compiler to generate the proper linkage information and proper routine code, you must insert a compiler directive at the entry points in the VAX MACRO source.

2.2.1 Linkage Section

On Alpha systems, all external (out-of-module) references are made through a linkage section. The linkage section is a program section (psect) containing:

  • Addresses of external variables
  • Constants too large to fit directly in the code stream
  • Linkage pairs
  • Procedure descriptors

A linkage pair is a data structure used when making a call to an external module. The linkage pair contains the address of the callee's procedure descriptor, and the entry point address. The linkage pair resides in the caller's linkage section; therefore, there may be several linkage pairs for a particular routine, one in each caller's linkage section. Linkage pairs are not used for module-local calls, since the compiler can refer to the callee's frame descriptor directly.

A procedure descriptor is a data structure that provides basic information about a routine, such as register and stack usage. Each routine has one unique procedure descriptor, and it is located in its linkage section. The procedure descriptor is normally not accessed at run time. Its primary use is for interpreting the frame in case of exceptions, by the debugger, for example.

For more information about these and other Alpha data structures, see the OpenVMS Calling Standard.

2.2.2 Prologue and Epilogue Code

To mimic the behavior of VAX subroutines, the compiler must generate code at the entry and exit of each routine. This code emulates the functions that are done by the VAX hardware, and is called the prologue and epilogue code.

In the prologue code, the compiler must allocate stack space to save any necessary context. This includes saving any registers that will be preserved by the routine and saving the return address. If this is a CALL routine, it also includes establishing a new stack frame and changing the frame pointer (FP), and may include further manipulation and storage of the input parameters (see Section 2.3).

In the epilogue code, the compiler must restore any necessary registers, stack frame information, and the return address, and trim the stack back to its original position.

2.2.3 When to Declare Entry Points

Any code label that is a possible target of a CALLS, CALLG, JSB, BSBW, or BSBB instruction must be declared as an entry point. In addition, any code label must be declared as an entry point using a .JSB_ENTRY or .JSB32_ENTRY directive if:

  • The label can be the target of a global (cross-module) JMP, BRB, or BRW instruction.
  • The label can be the target of an indeterminate branch (such as BRB @(R10)), where the address of the label has been stored in R10, even if the reference and the label are within the same module.
  • The address of the label is stored in a register or memory location, even if it is never accessed by the current module.

The OpenVMS calling standard for Alpha computers does not provide a way to access indeterminate code addresses directly. All such accesses are accomplished using a procedure descriptor to describe the routine and the code address. When a code label address is stored, the compiler does not know if that address will be referenced only by the current module, or whether it may be accessed by another MACRO module or another module written in another language. Whenever a source instruction stores a code address, the MACRO-32 compiler instead stores the procedure descriptor address for that code address so that other code can access it correctly. For a procedure descriptor to exist, the label must be declared as an entry point.

Likewise, when a stored address is used as a branch destination, the compiler does not know where that address came from, so it always assumes that the stored address is the address of a procedure descriptor and uses that descriptor to pass control to the routine.

2.2.4 Directives for Designating Routine Entry Points

Macros in STARLET.MLB generate directives for designating the entry points to routines. (Appendix B describes the format of each of these macros.) When assembled for VAX systems, the macros are null, except for .CALL_ENTRY; when compiled for Alpha systems, the macros expand to verify the arguments and generate the compiler directives. Therefore, you can use the following macros in common source modules:

  • The .CALL_ENTRY directive logically replaces the .ENTRY directive in MACRO-32 code. However, you do not need to replace the .ENTRY directive unless you want to use one of the .CALL_ENTRY clauses. If you replace the .ENTRY directives, note that you cannot do a massive replace with an editor because the arguments do not match.


    Since the .ENTRY directive is converted to an Alpha .CALL_ENTRY directive, any registers modified in the routine declared by .ENTRY will be automatically preserved. This is different from VAX MACRO behavior. See Section 2.3.2.
  • The .JSB_ENTRY directive indicates a routine that is executed as a result of a JSB, BSBB, or BSBW instruction. The .JSB32_ENTRY directive is used for specialized environments that do not require the preservation of the upper 32 bits of Alpha register values.
    The .JSB_ENTRY directive should also be used to declare entry points which are the targets of JMP or branch instructions from other modules, since such cross-module branches are implemented as JSBs by the compiler.
    Branches to stored code addresses, such as JMP (R0), are also treated as JSB instructions. Hence, potential targets must be declared with .JSB_ENTRY. The compiler warns you of this when you attempt to store a code label or when such a branch is used.
  • The .EXCEPTION_ENTRY directive designates exception service routines.

Previous Next Contents Index