5.7.2 The .EXE File Format

An .EXE file contains a file header and a relocatable-program image. The file header contains information that MS-DOS uses when loading the program, such as the size of the program and the initial values of the registers. The file header also points to a relocation table containing a list of pointers to relocatable-segment addresses in the program image.

The form of the file header corresponds to that of the EXEHEADER structure:

EXEHEADER STRUC

exSignature dw 5A4Dh ;.EXE signature

exExtraBytes dw ? ;number of bytes in last (partial) page

exPages dw ? ;number of whole and part pages in file

exRelocItems dw ? ;number of pointers in relocation table

exHeaderSize dw ? ;size of header, in paragraphs

exMinAlloc dw ? ;minimum allocation

exMaxAlloc dw ? ;maximum allocation

exInitSS dw ? ;initial ss value

exInitSP dw ? ;initial sp value

exCheckSum dw ? ;complemented checksum

exInitIP dw ? ;initial ip value

exInitCS dw ? ;initial cs value

exRelocTable dw ? ;byte offset to relocation table

exOverlay dw ? ;overlay number

EXEHEADER ENDS

For a full description of the EXEHEADER structure, see Section 5.8, “Structures.”

The program image, which contains the processor code and initialized data for a program, starts immediately after the file header. Its size, in bytes, is equal to the size of the .EXE file minus the size of the file header, which is equal to the value in the exHeaderSize field multiplied by 16. MS-DOS loads the .EXE program by copying this image directly from the file into memory and then adjusts the relocatable-segment addresses specified in the relocation table.

The relocation table is an array of relocation pointers, each of which points to a relocatable-segment address in the program image. The exRelocItems field in the file header specifies the number of pointers in the array, and the exRelocTable field specifies the file offset at which the relocation table starts. Each relocation pointer consists of two 16-bit values: an offset and a segment number.

To load an .EXE program, MS-DOS first reads the file header to determine the .EXE signature and calculate the size of the program image. It then attempts to allocate memory. First, it adds the size of the program image to the size of the PSP and to the amount of memory specified in the exMinAlloc field of the EXEHEADER structure. If the total exceeds the size of the largest available memory block, MS-DOS stops loading the program and returns an error value. Otherwise, it adds the size of the program image to the size of the PSP and to the amount of memory specified in the exMaxAlloc field of the EXEHEADER structure. If this second total is less than the size of the largest available memory block, MS-DOS allocates the amount of memory indicated by the calculated total. Otherwise, it allocates the largest possible block of memory.

After allocating memory, MS-DOS determines the segment address, called the start-segment address, at which to load the program image. If the value in both the exMinAlloc and exMaxAlloc fields is zero, MS-DOS loads the image as high as possible in memory. Otherwise, it loads the image immediately above the area reserved for the PSP.

Next, MS-DOS reads the items in the relocation table and adjusts all segment addresses specified by the relocation pointers. For each pointer in the relocation table, MS-DOS finds the corresponding relocatable-segment address in the program image and adds the start-segment address to it. Once adjusted, the segment addresses point to the segments in memory where the program's code and data are loaded.

Then MS-DOS builds the 256-byte PSP in the lowest part of the allocated memory, setting the AL and AH registers just as it does when loading .COM programs. MS-DOS uses the values in the file header to set the SP and SS registers and adjusts the initial value of the SS register by adding the start-segment address to it. MS-DOS also sets the ES and DS registers to the segment address of the PSP.

Finally, MS-DOS reads the inital CS and IP values from the program's file header, adjusts the CS register value by adding the start-segment address to it, and transfers control to the program at the adjusted address.