How MS-DOS 6.22 Executes 16-Bit Real Mode Binaries
Executing a 16-bit real-mode binary in MS-DOS 6.22 is a low-level
process that involves interpreting the binary format, allocating
physical memory, preparing execution metadata, and directly configuring
the x86 CPU registers. The operating system utilizes the INT 21h EXEC
system service to distinguish between flat .COM files and
relocatable .EXE files, constructs a 256-byte Program
Segment Prefix (PSP) in conventional memory, resolves any necessary
segment fixups, and transfers execution control directly to the
microprocessor within the 1 MB real-mode address space.
Binary Invocation and the EXEC Service
When a user or batch script runs an executable file from the command
line, COMMAND.COM parses the input string, locates the
specified file on disk, and invokes the MS-DOS EXEC function:
Interrupt 21h, Function 4Bh (Load and Execute
Program).
DOS opens the target file, reads its initial bytes, and determines its format:
- COM Binaries: Flat memory models containing raw machine code with no file header, capped at roughly 64 KB (one segment minus the 256-byte PSP).
- EXE Binaries: Structured files identified by the
signature ASCII characters
MZ(0x4D, 0x5A) in the first two bytes, indicating an MZ-format header with relocation data.
Memory Allocation via MCBs
MS-DOS manages conventional memory (the first 640 KB) using a linked list of Memory Control Blocks (MCBs). Each MCB contains an identifier byte, the owning process ID, and the size of the contiguous memory block that follows it.
- For .COM Files: DOS requests the largest available
contiguous block of memory. By default, MS-DOS allocates all remaining
conventional memory to the
.COMprogram. - For .EXE Files: DOS reads the
MINALLOCandMAXALLOCfields from the MZ header. It computes the required paragraph count (16-byte blocks) to hold the program image plus its uninitialized data and stack, then traverses the MCB chain using a first-fit or best-fit strategy to allocate the necessary space.
Constructing the Program Segment Prefix (PSP)
Before loading the binary code, DOS creates a standardized 256-byte (100h) data block called the Program Segment Prefix (PSP) at the base of the allocated segment. The PSP acts as a control interface between the running binary and DOS, containing:
- Offset 0x00–0x01: An
INT 20hinstruction (exit to DOS) for backward compatibility with CP/M. - Offset 0x02–0x03: The segment address of the top of allocated memory.
- Offset 0x0A–0x15: Saved vectors for the termination
address (
INT 22h), Ctrl-C exit (INT 23h), and critical error handler (INT 24h). - Offset 0x16–0x17: Parent process segment address.
- Offset 0x18–0x2B: The Job File Table (JFT), tracking default open file handles (stdin, stdout, stderr, stdaux, stdprn).
- Offset 0x2C–0x2D: Segment address of the process environment block.
- Offset 0x80–0xFF: The Command Tail (raw command-line arguments) and the default Disk Transfer Area (DTA).
Loading the Program Image
The mechanism for reading the executable file from disk into memory
depends entirely on whether the target is a .COM or an
.EXE file.
Loading .COM Programs
Because a .COM file is a direct memory image, DOS reads
the entire file into memory starting immediately after the PSP at offset
0x0100 within the allocated segment. No segment adjustment,
relocation, or header parsing occurs.
Loading .EXE Programs and Handling Relocations
An .EXE file contains structured code and data designed
to span multiple 64 KB segments:
- Header Parsing: DOS reads the MZ header to extract the header size, image size, initial register states, and the file offset of the Relocation Table.
- Reading the Image: DOS loads the binary image into memory directly following the PSP, aligning it on a paragraph boundary.
- Relocation Processing: Because real mode addresses
depend on where the program resides in physical memory, hardcoded
segment references within the binary must be adjusted:
- DOS reads the relocation table, which consists of
segment:offsetpointers referencing every 16-bit segment value inside the loaded image. - For every entry, DOS adds the base segment address where the program was loaded to the word located at the target address. This process patches all internal segment pointers so they point to valid physical memory locations.
- DOS reads the relocation table, which consists of
Register Initialization and Execution Handoff
Once the memory image is prepared, MS-DOS prepares the CPU's general-purpose and segment registers for execution.
.COM State Setup
- Segment Registers (CS, DS, ES, SS): All point to the base segment of the PSP.
- Instruction Pointer (IP): Initialized to
0x0100(the entry point following the PSP). - Stack Pointer (SP): Set to
0xFFFE(the top of the 64 KB segment, or the memory boundary if less than 64 KB is available). A word of0x0000is pushed onto the stack. - General Registers: Cleared to zero (or specific BIOS drive flags where applicable).
.EXE State Setup
- Code Segment (CS) and Instruction Pointer (IP): Initialized to the start address specified in the MZ header, offset by the program's base load segment.
- Data Segment (DS) and Extra Segment (ES): Set to the base segment of the PSP, ensuring the program can immediately access its command tail and environment variables.
- Stack Segment (SS) and Stack Pointer (SP): Derived directly from the MZ header values, with SS adjusted by the program's base segment.
The Real-Mode Jump
Because MS-DOS 6.22 runs as a single-tasking operating system without
hardware protection rings or virtual memory paging, the operating system
executes a far jump (JMP FAR CS:IP) or an IRET
instruction directly to the entry point. The 16-bit binary gains
unmediated control over the CPU, using the standard segmented memory
model (Segment * 16 + Offset) to access memory and using
software interrupts (INT 21h, INT 10h,
INT 13h) to request operating system and BIOS services.