
                Microsoft Segmented Executable Format
                -------------------------------------
                                 5/05/87

This document defines the Segmented Executable format, which is a
superset of the MS-DOS 2.x and 3.x .EXE format (hereafter called DOS
3.x).  The purpose of the segmented-executable format is to provide
the information needed to support the dynamic linking and segmentation
capabilities provided by OS/2, MS-DOS 4.0, and MS Windows.  Also,
information needed for protected mode is provided.

The DOS 3.x .EXE format has been extended as follows:

    - The word at offset 18h in the existing .EXE file contains the
      relative byte offset to the relocation table.  If this offset
      is 40h, then the double word at offset 3Ch is assumed to be
      the relative byte offset from the beginning of the file to the
      beginning of the new format executable header.  A new format
      .EXE file is identified if the new executable header contains
      a valid signature.  If the signature is not valid the file is
      assumed to be an old format .EXE file.  The remainder of the
      old format header will describe a DOS 3.x program, the stub. The
      stub may be any valid program but will typically be a program
      which displays an error message, emulates the new-format program,
      or brings in a loader that can handle the job.
      See the picture below for the actual file layout.

    - This format will only be used for .EXE files that use the new
      memory model supported by OS/2, MS-DOS 4.0 and MS Windows.
      Old .EXE files will continue with the DOS 3.x file format.

    Note
    ====
    Throughout this specification, all unused fields and flag bits are
    reserved for future use and are expected to contain 0.

The new .EXE file has the following format:

        00h     -------------------
                |                 |
                | Old EXE Header  |
                |                 |
        20h     -------------------
                | reserved        |
                -------------------
                |                 |
        3Ch     | offset to new   | ---+
                | EXE header      |    |
        40h     -------------------    |
                | DOS 3.x Stub    |    |
                |   Program &     |    |
                | Reloc. Table    |    |
                -------------------    |
                |                 |    |
        xxh     ------------------- <---
                |                 |
                | New EXE Header  |
                |                 |
                -------------------
                |                 |
                |  Segment Table  |
                |                 |
                -------------------
                |   Resource      |
                |     Table       |
                -------------------
                |    Resident     |
                |     Name        |
                |     Table       |
                -------------------
                |  Module Ref     |
                |     Table       |
                -------------------
                |    Imported     |
                |     Names       |
                |     Table       |
                -------------------
                |     Entry       |
                |     Table       |
                -------------------
                |  Non-Resident   |
                |     Name        |
                |     Table       |
                -------------------
                | Seg #1 Data     |
                | Seg #1 Info     |
                -------------------
                        .
                        .
                        .
                -------------------
                | Seg #n Data     |
                | Seg #n Info     |
                -------------------
                | Debug           |
                | Information     |
                -------------------



    New Executable Header
    =====================

      00h   DW  signature word
                "N" is low order byte
                "E" is high order byte
      02h   DB  version#
      03h   DB  revision#
      04h   DW  Entry Table file offset relative to beginning of new
                EXE header
      06h   DW  #bytes in Entry Table
      08h   DD  32-bit checksum of entire contents of file
                (with these words taken as 00 during the calculation)
      0Ch   DW  flag word
                  0000h = NOAUTODATA
                  0001h = Shared automatic data segment (SINGLEDATA)
                  0002h = Instance automatic data segment (MULTIPLEDATA)
                  0004h = Per-process library initialization (INITINSTANCE)
                  0008h = Runs in protected mode only (PROTMODE)
                  0008h = runs in protected mode only
                  0010h = 8086 instructions present
                  0020h = 286 instructions present
                  0080h = floating point instructions present
                  2000h = errors detected at link time
                  8000h = Library module (SS:SP info is invalid, CS:IP
                          points to initialization procedure that is
                          called with AX = the module handle. The
                          procedure must execute a far return to the
                          caller, with AX != 0 to indicate success and
                          AX = 0 to indicate failure to initialize. DS =
                          the library's data segment if the SINGLEDATA
                          flag is set and the caller's DS otherwise.)
                          A program can only contain dynamic links to
                          executables that have this flag set.

      0Eh   DW  segment# of automatic data segment (index into segment
                table)
                set to zero if SINGLEDATA and MULTIPLEDATA flag bits are
                reset
      10h   DW  initial size of dynamic heap added to data segment in
                bytes (0 if no local alloc)
      12h   DW  initial size of stack added to data segment in bytes
                (0 if SS!=DS)
      14h   DD  segment#:offset of CS:IP
      18h   DD  segment#:offset of SS:SP
                Segment# is an index into the module's segment table.
                The first entry in the segment table is segment number 1.
                If SS = automatic data segment and SP = 0,
                the stack pointer is set to the top of the automatic
                data segment just below the additional heap area.

                         +-------------------------+
                         | additional dynamic heap |
                         +-------------------------+ <- SP
                         |    additional stack     |
                         +-------------------------+
                         |   loaded data segment   |
                         +-------------------------+ <- DS, SS

      1Ch   DW  #of entries in Segment Table
      1Eh   DW  #of entries in Module Ref Table
      20h   DW  #bytes in Non-Resident Name Table
      22h   DW  Segment Table file offset relative to beginning of new EXE
                header
      24h   DW  Resource Table file offset relative to beginning of new
                EXE header
      26h   DW  Resident Name Table file offset relative to beginning of
                new EXE header
      28h   DW  Module Ref Table file offset relative to beginning of new
                EXE header
      2Ah   DW  Imported Names Table file offset relative to beginning of
                new EXE header
      2Ch   DD  Non-Resident Name Table offset relative to beginning of
                file
      30h   DW  #of movable entries in Entry Table
      32h   DW  logical sector alignment shift count, log(base 2) of
                segment sector size (default 9)
      34h   DW  #of resource entries
      36h -
      3Eh   DW  reserved, currently 0's


    Segment Table
    =============

        "N" segment table entries:

            The first entry in the segment table is segment number 1.
            DW  n-byte logical sector offset to contents of the segment
                data relative to beginning of file (zero means no file
                data)
            DW  length of segment in file, in bytes (zero means 64K)
            DW  flag word
                  0007h = TYPE_MASK     ; segment type field
                  0000h = CODE          ; code segment type
                  0001h = DATA          ; data segment type
                  0008h = ITERATED      ; segment data is iterated
                  0010h = MOVABLE       ; segment is movable (OS/2 ignores)
                  0020h = SHARED        ; segment can be shared
                  0040h = PRELOAD       ; segment is preloaded
                  0080h = ERONLY        ; execute only if code segment
                                        ; read only if data segment
                  0100h = RELOCINFO     ; set if segment has reloc records
                  0200h = CONFORM       ; segment is conforming
                  0C00h = SEGDPL        ; I/O privilege level
                  1000h = DISCARD       ; discardable segment (OS/2
                                        ; ignores)
                  4000h = HUGE          ; huge segment: length of segment
                                        ; and minimum allocation sizes are
                                        ; in units of segment sector size
            DW  minimum allocation size in bytes
                Total size of the segment 0 means 64K


    Resource Table
    ==============

        DW  alignment shift count for resource data

        "N" iterations of record:
         |  DW  type ID - integer type if high order bit is set (8000h)
         |      otherwise offset to type string, relative to
         |      beginning of the resource table
         |      = 0 marks end of resource records
         |
         |  DW  #resources for this type
         |  DD  Reserved
         |   |
         |   |  "#resources" copies of Resource Entry (8 bytes)
         |   |
         |   |  DW  file offset to contents of the resource data relative
         |   |      to beginning of file. Offset is in terms of alignment
         |   |      units specified at beginning of resource table.
         |   |  DW  length of resource in file (bytes)
         |   |  DW  flag word
         |   |        0010h = MOVEABLE  ; resource is not fixed
         |   |        0020h = PURE      ; resource can be shared
         |   |        0040h = PRELOAD   ; resource is not demand loaded
         |   |  DW  resource ID - integer type if high order bit is set
         |   |      (8000h) otherwise offset to resource string, relative
         |   |      to beginning
         |   |  DD  Reserved
          \   \     of the resource table

        Resource type and name strings stored at end of resource table
                Note that these strings are NOT null terminated

            DB  length of type or name          ; = 0 if end of resource
                                                ;   table
            DB  ASCII text of type or name      ; Case sensitive


    Resident or Non-resident Name Table Entry (3 + n bytes)
    =========================================

        The strings are CASE SENSITIVE and NOT NULL TERMINATED

        DB  Length of string            ; =0 if no more strings in table
        DB  ASCII text of string
        DW  ordinal# (index into entry table)

        First string in resident name table is the module name.

        First string in non-resident name table is the module description.


    Module Reference Table
    ======================

        "N" entries of the form:  (1-based)

            DW  offset within Imported Names Table to module name string


    Imported Names Table (1 + n bytes)
    ====================

        The strings are CASE SENSITIVE and NOT NULL TERMINATED

        DB  0                           ; to ensure non-zero first entry
                                        ; offset

        "N" entries of the form:

            DB  Length of name
            DB  ASCII text of name


    Entry Table     (1 based)
    ===========

        "N" bundles of entry definitions.  The ordinal value of an entry
         |  point is its ordinal within the entry table, counting the
         |  first entry as ordinal #1.  The loader must scan over the
         |  bundles until it finds the bundle containing the entry point;
         |  the loader can then multiply by entry size to index the
         |  proper entry.
         |
         |  The linker forms bundles in the densest manner it can, given
         |  the restriction that it cannot reorder entry points to improve
         |  bundling because other EXE files may refer to entry points
         |  within this one by their ordinal in this table.
         |
         |  DB  #entries in this bundle.  All records in one bundle are
         |      either movable or refer to the same fixed segment.
         |      Equal to 0 if no more bundles in Entry Table.
         |
         |  DB  segment indicator for this bundle
         |   |    00h - Unused, bundle not present, next bundle count
         |   |    follows
         |   |    FFh - Movable segment, # is in entry
         |   |    otherwise is segment # of fixed segment
         |   |
         |   |   If fixed segment, entries are 3 bytes:
         |   |     DB  flags
         |   |           01h = set if entry is exported
         |   |           02h = set if entry uses global (shared) data
         |   |                 segment
         |   |                 "mov ax,#ds-value" must be the 1st
         |   |                 instruction in the prolog of this
         |   |                 entry.  This flag may only be set
         |   |                 for SINGLEDATA library modules.
         |   |           F8h = # of parameter words
         |   |     DW  offset
         |   |   Else movable segment, entries are 6 bytes:
         |   |     DB  flags
         |   |           01h = set if entry is exported
         |   |           02h = set if entry uses global (shared) data
         |   |                 segment
         |   |           F8h = # of parameter words
         |   |     int 3Fh
         |   |     DB  segment#
          \   \    DW  offset


    Per segment data:
    ================

      If ITERATED
        DW  #iterations
        DW  #bytes of data
        DB  data bytes
      else
        DB  data bytes


      If RELOCINFO
        DW  #relocation items
        |
        | Relocation Item: (8 bytes)
        |
        |   DB  source type
        |         0Fh = SOURCE_MASK
        |         00h = LOBYTE
        |         02h = SEGMENT
        |         03h = FAR_ADDR        (32-bit pointer)
        |         05h = OFFSET          (16-bit offset)
        |
        |   DB  flags
        |         03h = TARGET_MASK
        |         00h = INTERNALREF
        |         01h = IMPORTORDINAL
        |         02h = IMPORTNAME
        |         03h = OSFIXUP
        |         04h = ADDITIVE
        |
        |   DW  offset within this segment of source chain
        |       If ADDITIVE flag set, then add target value to source
        |       contents, instead of replacing source and following the
        |       chain.
        |       The source chain is a FFFFh terminated linked list within
        |       this segment of all references to the target.
        |
        |   Target
        |     INTERNALREF
        |       DB  segment# for fixed segment or FFh if movable
        |       DB  0
        |       DW  offset into segment if fixed
        |           index into Entry Table iff movable
        |
        |     IMPORTNAME
        |       DW  index into module ref table
        |       DW  offset within Imported Names Table to proc. name
        |           string
        |
        |     IMPORTORDINAL
        |       DW  index into module ref table
        |       DW  procedure ordinal#
        |
        |     OSFIXUP
        |       DW  Operating system fixup type
        |         Floating-point fixups
        |             0001h = FIARQQ, FJARQQ
        |             0002h = FISRQQ, FJSRQQ
        |             0003h = FICRQQ, FJCRQQ
        |             0004h = FIERQQ
        |             0005h = FIDRQQ
        |             0006h = FIWRQQ
         \      DW  0

    Debug Information
    =================
        Any debug information will be at the end of the executable.
        No information about it will appear in the header, so executable
        files may be longer than the file length indicated in the
        header.


