X86 Porting Considerations

From VSI OpenVMS Wiki
Jump to: navigation, search

x86 Porting Considerations are things that application developers are advised to consider when porting an application to x86. This is a community-maintained list; it should not be considered a full list of architectural differences or an official porting document. Although VMS Software maintains the wiki and may make changes to this document, it assumes no responsibility for any errors or omissions.

General Porting Considerations

  • Machine instructions specific to certain architectures.
  • Assumptions on the number of registers.
  • Code that relies on the VAX, Alpha, or IA64 calling standards.
  • Code that is conditionalized or includes logic that assumes it is running on a certain architecture (see examples in the VSI OpenVMS Porting Applications from VSI OpenVMS Alpha to VSI OpenVMS Industry Standard 64 for Integrity Servers).
  • Code that depends on a different architecture's internal data structures.
  • Code that references terminal drivers that do not use the call interface.
  • Code that contains user-written threading.
  • Code that uses nonstandard or undocumented code practices or interfaces.
  • Code that contains unaligned data.
  • Code that uses privileged interfaces or operates at inner access modes.

Architectural and Related Differences

  • Logical names that point to the location of shareable and loadable images are different: X86$LIBRARY for x86-64, IA64$LIBRARY for I64, ALPHA$LIBRARY for Alpha, and SYS$LIBRARY for VAX links; X86$LOADABLE_IMAGES on x86-64 systems, IA64$LOADABLE_IMAGES on I64 systems, or ALPHA$LOADABLE_IMAGES on Alpha systems respectively.
  • An x86-64 symbol vector entry is a pair of quadwords, An I64 symbol vector entry is a single quadword.
  • For x86-64 images, a function symbol's value is always a code address. There is no GP and no short data segment. For x86-64 images, the entry in the symbol vector with the index value of 1 contains the values 00002080 and 80000020.
  • Alignment on the default target page size, which is 8 KB for x86-64 and 64 KB for I64 linking. You can override this default by specifying the /BPAGE qualifier.
  • Sections Embedded in Code Segments (x86-64 only) – see the Linker Manual.
  • Procedure Linkage Table (PLT) Import Stubs (x86-64 only) – see the Linker Manual.
  • On x86-64, all segments within a shared library must have the same positions relative to each other that they were given by the linker. The image activator is free to load segments in a shareable image independently of each other. To allow segments to be loaded independently, VMS compilers generate code that uses indirect addressing. This way, the only segments whose relative positions have to be maintained are the code segment, the unwind segment, and the Global Offset Table segment. The linker flags those segments. A segment which requires the linker-given position to the preceding segment is flagged as "Fixed Offset" (Fof). In an image with code segments in multiple clusters, each cluster will have its own unwind segment and Global Offset Table so that their relationship can be maintained. The image activator and the install utility maintain the relative positions of these segments.
  • The x86-64 linker places code segments in the P2 region by default and uses the default page size of 2000 hexadecimal. The /SEGMENT=CODE=P0 option can be specified to place code segments in the P0 region. Non-code segments (without the ALLOC_64BIT attribute specified) are placed in the P0 region by default. The I64 linker places segments in the P0 region by default and uses the default page size of 10000 hexadecimal. The /SEGMENT=CODE=P2 option can be specified to place segments in the P2 region. On x86-64 systems, the first P0 segment is placed at 2000 hexadecimal. On I64 systems, the first P0 segment is placed at 10000 hexadecimal, leaving the first page unused as a guard page.
  • For the I64 symbol vector, you can set or clear the SHORT attribute. For the x86-64 symbol vector, setting or clearing the SHORT attribute is ignored.
  • On I64, to move all code into P2 space, you can use the /SEGMENT_ATTRIBUTE=CODE=P2 command qualifier. On x86, to move all code into P0 space, you can use the /SEGMENT_ATTRIBUTE=CODE=P0 command qualifier. Please note, that if you use clusters in the same link command (with linker options) and if EXE sections are put on specific clusters, setting ALLOC_64BIT does not change the per cluster segment creation. You then will see more than one executable segment with base addresses in P2 space.
  • Some segments created by linkers on IA64 and x86-68 are different (see the Linker manual for more information):
    • Global Offset Table segments (x86-64 only)
    • Unwind segments (I64 only)
    • Short data segments (I64 only)
    • Signature segments (I64 only)
    • Dynamic segments
  • On x86-64 systems, when an executable image calls a function in a shareable image, the call goes through one or two linker-generated code stubs.
  • On I64 systems, at run-time, when the image activator maps the shareable image into memory, it calculates the actual locations of the routines and relocatable data within the image and stores these values in its symbol vector. The image activator then fixes up the references to these symbols in the executable image.
  • Check the format of the LINK command; not all qualifiers are available for x86. Default values can also be different: for instance, the default value of the page size qualifier is 8 KB for x86 and 64 KB for IA64. The default value in x86 is /THREAD, which may not be appropriate for older architectures.
  • For I64 systems, a hardware extension is used as described in the Intel Itanium Processor-specific Application Binary Interface. For x86-64 systems, a hardware extension is used as described in the System V Application Binary Interface, AMD64 Architecture Processor Supplement.
  • When porting an application from IA64 to x86-64, be aware that the image layout may change in an incompatible way – although the compile and link commands/options did not change. This is an architectural difference.
  • On IA64, the compiler may generate short data, which is accessed in an efficient way. The IA64 linker always collects short data to the DEFAULT CLUSTER, no matter where the object module that defines this short data is collected. That is, in a partially protected shareable image, an object module may be collected into a protected linker cluster, but its short data may be collected into a unprotected cluster, and so it is not protected. User-mode code in the shareable image can write to it. On x86-64, there is no short data. All data defined in an object module will go where the module goes (except the defining PSECT, which is moved with an explicit COLLECT option). That is, on x86-64, for partially protected shareable images, all data defined by an object module which is collected into a protected linker cluster will be protected. User-mode code in the shareable image can not write to it.
  • VSI recommends that any privileged image linked /SYSEXE should be relinked for the V9.2 or subsequent releases because data structures and interfaces are subject to change for each new version.
  • Currently, the x86-64 cross compilers set the debug language to C by default. This means that when the debugger regains control, the language is set to C, even if the module being debugged was written in another language. The way to work around this problem is simply to use the SET LANGUAGE command to set the default language to that which is being debugged.
  • User-written x86-assembler code must follow the VSI OpenVMS calling standard (see the VSI OpenVMS Calling Standard manual) to provide exception handling information that is used by the exception handling mechanism to find a handler in one of the callers of the assembler module. Without that information, exception handling can only call the last chance handler, which means the application will likely not be able to handle the exception.
  • Review the CRTL manual for CRTL changes. For example, the interface for the function isatty has been modified. Previously, in case of an error, the function returned -1. This is not compatible with the POSIX 1003.1 standard. This leads to errors that are hard to find. With this release, in case of an error, the function returns 0 and stores the error in errno. If your code assumes a return value of 0, this means that the fd is not a tty. If your code assumes a return value of -1, this means an error, you will need to change the code.
  • The implementation of variable argument lists on x86-64 is different than on Integrity and Alpha and may require source code changes, depending on how the lists are used.

See also