DOS is able to load and execute two types of program files -- COM and EXE.
Because of the segmented address space of the Intel 8088/80x86 CPUs and
the fact that JMPs and CALLs are address-relative, either type of program
may be loaded and executed at any paragraph address in conventional
memory. Thus, code can be made resident in "low" memory and other code
can be loaded and executed above it in memory. Programs are never written
with the assumption that they'll be loaded at a certain address (except
the boot sector and some self-booting, copy-protected games).
A COM-format file is a binary image of the code and data of the
program. The file must be less than 64K, and no segment-address
An EXE-format file contains an EXE Header that directs the loader in
performing adjustments to segment references in a load module.
Before either a COM- or EXE-format program is loaded, DOS selects a
segment address, called the PSP (Program Segment Prefix) as the load base
for the program. By default, DOS selects the lowest available address in
conventional memory, but it is possible to control the location via DOS
fn 58H. Then DOS performs these steps:
DOS Fn 4bH (EXEC) lets a parent program create a different environment.
For instance, a program can run COMMAND.COM, setting the DOS prompt to
include the text "Use EXIT to return to UltraProg>".
It places a text string identifying the program's load path at the end
of the environment (in DOS 3.0+).
It fills the fields of the PSP with information useful to the program
The amount of memory available to the program
line (Note: if you open the first FCB, it will overwrite part of the
The command parameters: text entered in the command line after the
program name (examine this for options and filename parameters)
It sets the AX register to indicate the validity of the drive IDs (if
any) of the filespec parameters entered on the command line:
if AL=0ffH, then the first drive ID was invalid
if AH=0ffH, then the second drive ID was invalid
EXE-format programs define multiple program segments, including a code,
data, and stack segment. The EXE file is loaded starting at PSP:0100. As
it is loaded, a bunch of information is read from the EXE Header at the
start of file and segment address-relocation is performed. This means
that references such as...
...must be adjusted to allow for the fact that the program is being loaded
into an arbitrarily-selected memory segment. See EXE Header for details
of the header and the relocation process.
After relocation, control is passed to the load module via a FAR jump to
the CS:IP that was read from the EXE header.
When the EXE-format program gets control:
DS and ES are set to the PSP
CS, IP, SS, and SP are set to values indicated in the EXE Header
The PSP.wNextSeg field is set to a value in the EXE header. Normally,
all of available memory is allocated to the program.
COM-format programs define a single segment. The bytes of the COM file
are read from disk and stored into memory starting at PSP:0100. Note that
a COM program can use multiple segments, but it must calculate or derive
segment addresses, using the PSP segment as a base.
Traditionally, COM programs have been preferred over EXE programs for
short assembly language utilities. They load faster since no segment
relocation is needed, and they take less disk space since the bytes of
the EXE header and the stack segment need not be present in the load
module. However, COM programs are starting to be phased out, since you
can't write OS/2- or Windows-specific programs in COM format.
Compilers and linkers may refer to COM programs as those using the "tiny"
CS, DS, ES, and SS are set the same as the PSP.
SP is set to the end of the PSP segment (usually 0fffeH, but it will be
lower if a full 64K is not available). The word at offset 06H of the
PSP is set to indicate how much of the program segment is available.
All system memory above the Program Segment is allocated to the
A word of 00H is pushed onto the stack.
IP is set to 100H (the first byte of the load module) by a JMP to
At one time (back in the days of DOS 1.1), it took several pages to
explain the Rube Goldberg scheme DOS provided for exit from a program.
It got easier starting with DOS 2.0. You can exit by:
Using DOS Fn 4cH (EXIT) at any time, regardless of register values.
Using DOS Fn 00H or INT 20H when your CS is the same as the PSP
Prior to DOS 2.0, you needed to save the PSP segment at startup. Then to
exit, you would PUSH it on the stack, PUSH a word of 00H, then do a FAR
RETurn. This sends control to PSP:0000 which contains the opcodes for
INT 20H. This ensures that CS is set as expected by DOS.
DOS Fn 4cH eliminates this complication, and it lets you return an
exit code to the parent process (usually COMMAND.COM) which can be tested
by the parent program or the "IF ERRORLEVEL" batch file command.
You may also terminate a program and make it permanently memory resident
(TSR), by using either INT 27H or DOS Fn 31H (KEEP). The latter has the
advantages that you can make more than 64K resident and you can return an
exit code that can be tested by the parent process.
TSR programs are handy for installing custom patches to various DOS and
BIOS services. It is the concept used by popup utilities such as SideKick
and TECH Help! (to name two popular instances).
All of its memory is freed, including the allocation for its copy of
fn 31H) the specified memory and your environment memory is preserved.
TSRs should explicitly free their environment if they won't need it
Its files are closed and file buffers flushed.
Redirection, if any, is cancelled.
Terminate (INT 22H) vectors are restored from the PSP.
Control is passed back to the parent, via a FAR JMP to the address that
was previously in the INT 22H vector.
TSR ........................ submenu of popup-program topics
DOS Fn 26H ................. build a PSP
DOS Fn 4bH (EXEC)........... load and execute programs
DOS Fn 62H ................. obtain PSP of the current program
from which you were loaded, etc.