Run a COM file

377 views
Skip to first unread message

Picard Damien

unread,
Oct 2, 2002, 2:41:58 AM10/2/02
to
Hi there,

What is the good conditions to run a .COM program, i try to write an OS a
little bit similar to DOS. So i'd like to know, state of the registers and
other before run this kind of file.

Thanks!

(Sorry for my bad english i'm french :))


Jawade

unread,
Oct 2, 2002, 3:37:58 PM10/2/02
to
In article <3d9a94aa$0$17439$626a...@news.free.fr>, pit...@hotmail.com
says...

> Hi there,
>
> What is the good conditions to run a .COM program, i try to write an OS a
> little bit similar to DOS. So i'd like to know, state of the registers and
> other before run this kind of file.

With this routine you can check the state of the DOS-registers
and flags at the moment they enty a .COM file:

BREAKPT pushf
call BreBGIN
BreBGIN push dx
push ax
mov dx,BreRGAX
mov ah,09
int 21h
pop ax
mov [BreTPAX],ax
call BreWORD ; Print AX
mov dx,BreRGBX
mov ah,09
int 21h
mov ax,bx
call BreWORD ; Print BX
mov dx,BreRGCX
mov ah,09
int 21h
mov ax,cx
call BreWORD ; Print CX
mov dx,BreRGDX
mov ah,09
int 21h
pop ax
call BreWORD ; Print DX
mov dx,BreRGSP
mov ah,09
int 21h
mov ax,sp
add ax,0004
call BreWORD ; Print SP
mov dx,BreRGBP
mov ah,09
int 21h
mov ax,bp
call BreWORD ; Print BP
mov dx,BreRGSI
mov ah,09
int 21h
mov ax,si
call BreWORD ; Print SI
mov dx,BreRGDI
mov ah,09
int 21h
mov ax,di
call BreWORD ; Print DI

mov ah,02h
mov dl,20h
int 21h
int 21h
mov dl,27h
int 21h
mov al,[BreTPAX]
cmp al,20h
jnc BreNOCO
mov al,20h
BreNOCO mov dl,al
int 21h
mov dl,27h
int 21h

mov dx,BreRGDS
mov ah,09
int 21h
mov ax,ds
call BreWORD ; Print DS
mov dx,BreRGES
mov ah,09
int 21h
mov ax,es
call BreWORD ; Print ES
mov dx,BreRGSS
mov ah,09
int 21h
mov ax,ss
call BreWORD ; Print SS
mov dx,BreRGCS
mov ah,09
int 21h
mov ax,cs
call BreWORD ; Print CS
mov dx,BreRGIP
mov ah,09
int 21h
pop ax
sub ax,0004
call BreWORD ; Print IP

mov ah,02
mov dl,20h
int 21h
int 21h
mov bx,0800h
mov si,BreBIT0+12
BreNEBI mov bp,0000
mov al,[si+1]
cmp al,'('
jnz BreNRBX
add si,0003
jmp BreRLBX
BreNRBX pop ax
push ax
test ax,bx
jz BreNZ01
mov bp,0030h
BreNZ01 add si,bp
mov ah,02
mov cx,0003
BreLP01 lodsb
mov dl,al
int 21h
loop BreLP01
sub si,bp
BreRLBX shr bx,1
jnc BreNEBI

mov dx,BreRGFL
mov ah,09
int 21h
pop ax
call BreWORD ; Print FL
mov cx,000Eh
mov dx,BreRGST
mov ah,09
int 21h
BreNXST mov ah,02h
mov dl,20h
int 21h
pop ax
call BreWORD ; Print st
cmp sp,0000
jz BreSTOP
loop BreNXST

BreSTOP mov ax,4C00h
int 21h

BreTPAX db 0000

BreRGAX db 'AX=$'
BreRGBX db ' BX=$'
BreRGCX db ' CX=$'
BreRGDX db ' DX=$'
BreRGSP db ' SP=$'
BreRGBP db ' BP=$'
BreRGSI db ' SI=$'
BreRGDI db ' DI=$'

BreRGDS db 13,10
db 'DS=$'
BreRGES db ' ES=$'
BreRGSS db ' SS=$'
BreRGCS db ' CS=$'
BreRGIP db ' IP=$'
BreRGFL db ' FL=$'
BreRGST db 13,10
db 'Stack:$'

BreBIT0 db ' () () () () NV UP DI () PL NZ () NA () PO () NC'
BreBIT1 db ' () () () () OV DN EI () NG ZR () AC () PE () CY'

BreWORD push ax ; Print AX hex uit.
mov al,ah ; Gebruikt: AX DL Flags (getest)
call BreBYTE
pop ax

BreBYTE push ax ; Print AL hex uit.
shr al,1 ; Gebruikt: AX DL Flags (getest)
shr al,1
shr al,1
shr al,1
call BreNIBB
pop ax
BreNIBB and al,0fh
cmp al,0ah
jc BreGOON
add al,07
BreGOON add al,30h
mov dl,al
mov ah,2 ;print
int 21h ; karakter (nibble) uit.
ret ;return


--
Groeten, Jawade.

"Oktober is nog wel geen winter, maar zie je die sneeuwpop daarginter?"

Bill Marcum

unread,
Oct 5, 2002, 2:14:38 PM10/5/02
to
You can see the state of the registers with DEBUG. Ralf Brown's
interrupt list should have information about the PSP (memory locations
CS:0 to CS:FF).

Matthias Paul

unread,
Oct 7, 2002, 1:08:53 PM10/7/02
to
On 2002-10-02, Picard Damien wrote:

> What is the good conditions to run a .COM program, i try to write
> an OS a little bit similar to DOS. So i'd like to know, state of
> the registers and other before run this kind of file.

For your convenience a few excerpts from some in-edit files for the
forthcoming RBIL62:

--------D-214B-------------------------------
INT 21 - DOS 2+ - "EXEC" - LOAD AND/OR EXECUTE PROGRAM
AH = 4Bh
AL = type of load
00h load and execute
01h load but do not execute, return debug info
03h load overlay (see #01591)
04h load and execute in background (European MS-DOS 4.0
only) "Exec & Go" (see also AH=80h)
DS:DX -> ASCIZ program name (must include extension)
ES:BX -> parameter block (see #01590,#01591,#01592)
CX = mode (subfunction 04h only)
0000h child placed in zombie mode after termination
0001h child's return code discarded on termination
Return: CF clear if successful
AX,BX,DX destroyed
if subfunction 01h, process ID set to new program's PSP;
get with INT 21/AH=62h
(Novell DOS 7+) if subfunction 03h, AX=SETVERed version
or 0000h.
CF set on error
AX = error code (01h,02h,05h,08h,0Ah,0Bh)
(see #01680 at AH=59h)
Notes: DOS 2.x destroys all registers, including SS:SP; one possible
work-around is to save the SS:SP stack pointer in a local
variable before calling INT 21h/AH=4Bh and restore the old
SS:SP afterwards (the CLI/STI in order to work around a bug
in early 8088 CPUs):
...
INT 21h ; INT 21h/4Bh
CLI
MOV SS,CS:stack_seg
MOV SP,CS:stack_ofs
STI
PUSH CS
POP DS
...
newer DOS versions (like 5 or 6) still destroy AX, BX, DX
because internally they call functions to deal with files,
allocating memory, etc. which set values to be returned in
the registers to the caller.
under ROM-based DOS, if no disk path characters (colons or
slashes) are included in the program name, the name is
searched for in the ROM module headers (see #01595) before
searching on disk
for functions 00h and 01h, the calling process must ensure that
there is enough unallocated memory available; if necessary,
by releasing memory with AH=49h or AH=4Ah
for function 01h, the AX value to be passed to the child
program is put on top of the child's stack; the info returned
by function 01h is used by debuggers.
function 01h was undocumented prior to the release of DOS 5.0.
function 02h is not implemented in any known DOS issues so
far - its originally intended purpose is not currently
known.
function 03h is used by the DOS BIOS to load device drivers.
for function 03h, DOS assumes that the overlay is being loaded
into memory allocated by the caller.
for function 03h, the MS-DOS/PC DOS (at least 6.x+) kernel
checks a special internal flag which indicates, if the
system is still in SYSINIT. Under these DOS versions DEVICE=
statements are reordered and always get executed prior to
INSTALL= statements, hence this flag indicates that the
INT 21h/AH=4Bh overlay call must have been issued
by the DOS BIOS in order to load a device driver.
Since device drivers don't have a PSP to store the SETVERed
version in there, the kernel patches the corresponding
SETVERed version for the device driver into a special PSP
data structure stored in the DOS BIOS init??? code. This
allows to retrieve SETVERed versions even for device drivers
at least until the next call to INT 21h/AX=4B03h was
issued. This usually allows to fake DOS versions during a
device driver's initialization (where DOS version checks
usually occur), but is not completely reliable and may
return invalid faked versions afterwards.
for function 03h, DR DOS "Panther", Novell DOS 7+ (still DR-DOS
7.05) undocumentedly return AX = SETVERed version or zero for
similar purposes, but the DOS BIOS does not currently make
use of this info. This is not supported by NetWare PalmDOS
and earlier versions of DR DOS.
(Just in case future issues would have to drop this special
case for compatibility with DOS, it is recommended to call
this function with a magic BP=0EDCh which would then still
return the special AX return code. It might be possible to
store the SETVERed version in two of the unused BYTEs of
the device driver's MCB header in the future.)
under OS/2 the FSFILTER.SYS program takes over INT 21h/AH=4Bh
and does not return a proper AX value, hence Novell DOS 7+
(since 1994-05-24) directly pokes the version number into
the PSP instead of relying on the AX return.
some versions (such as DR DOS 6.0) check the parameters and
parameter block and return an error if an invalid value
(such as an offset of FFFFh) is found
under RxDOS 6.0-7.1.6, subfunction 03h has been extended to not
require a preallocated block of memory. If the address of the
overlay block is zero, the function will predetermine the
program size based on its type, that is, whether it is a
.COM or .EXE file.
background programs under European MS-DOS 4.0 must use the new
executable format
this function ignores the filename extension, instead checking
the first two bytes of the file to determine whether there
is a valid .EXE header (see #01594); if not, the file is
assumed to be in .COM format. If present, the file may be
in any of several formats which are extensions of the
original .EXE format (see #01593)
the .COM executable format was not intended to support larger
than 64 Kb memory images, however, some DOS issues can deal
with larger files to a varying degree.
MS-DOS 6.0 will read only the first 64 Kb-PSP of the image in
case it would be larger, the stack pointer will be set to
SS:FFFEh.
DOS-C (1996) seems to load up to 64 Kb of data with unknown
consequences for the PSP (wrap around???) and the stack at
SS:FFFEh-something???
RxDOS 6.0-7.1.6 will load .COM-format executables into memory
even when they are larger than 64 Kb, but the stack pointer
will be created at the end of the first segment, and thus
will overwrite parts of the image if this has not been taken
into account.
PTS-DOS 6.51 and S/DOS 1.1 will completely discard
.COM-format executables larger than FEFFh bytes (64 Kb-PSP)
file size.
.COM-format executables begin running with the following
register values:
AL = 00h if first FCB has no or a valid drive letter,
FFh if no valid drive letter
AH = 00h if second FCB has no or a valid drive letter,
FFh if no valid drive letter
CS,DS,ES,SS = PSP segment
IP = load offset (0100h)
SP = offset of last WORD available in first 64K segment
(that is FFFEh) or the maximum size of memory
available in the block the program is loaded into
for both, the program plus at least 256 bytes
stack (which may change with loadhigh region
support options), whatever is smaller, or 00FEh
on very early DOS issues (DOS v1???).
Notes: officially, BX,CX,DX,SI,DI,BP,Flags, as well as
the high register words on 386+ CPUs are
undefined and should not be relied upon in
programs
AL and AH are always 00h under both, DESQview
and RxDOS 6.0-7.1.6, while under DOS-C they
are always FFh (probably also under FreeDOS -
subject to change).
AX appears to be zero under MS-DOS/PC DOS
DEBUG, but the DR-DOS 7.xx DEBUG.EXE sets
up the AH and AL values according to the
results of the first and second FCB tests,
however, the results are different from the
values for INT 21h/AH=4Bh (00h for no valid
or default drive letter, 01h..1Ah for A:..Z:,
many other chars x: appear to be returned
with either +B0h, +40h, or +20h added to
the letter, for example 0:..9: resulting
in D0h..D9h???).
BX:CX holds the size of the program under RxDOS
6.0-7.1.6, similar to what usually happens
under other DOSes when loading a program in
DEBUG.EXE.
Both registers are set to 0000h under DOS-C
(1996) and the later FreeDOS (BETA 7).
DX,SI,DI,BP are all set to 0000h under RxDOS
6.0-7.1.6, DOS-C, and FreeDOS, but not under
operating sytems of the MS-DOS/PC DOS or
DR-DOS families. These registers are set
to 0000h under DEBUG.EXE.
the Flags are set to 0000h under RxDOS
6.0-7.1.6, DOS-C, and FreeDOS, but not
under the other DOSes.
the stack holds a WORD of 0000h so that the
program can be terminated with a simple RETN,
which falls into the CP/M-style exit point,
the INT 20h at offset +00h in the PSP, similar
to just jumping to offset +00h or performing
a INT 20h directly.
apparently, DR DOS before 1988-08-18 tried to
reserve 4000h bytes of stack for .COM
programs, not just the usual 100h. This was
changed for ACCPAC.
BUGs: some badly written utilities seem to rely on the
D-Flag being cleared on startup, a condition
that must not necessarily be true, so noone
should rely on this.
some obscure "smallest program contests"
exercises rely on the high byte of BP equal
to 09xxh on entry, a condition that accidently
exists in several vesions of MS-DOS
COMMAND.COM, including MS-DOS 5.0, Windows95
OSR 2.x DOS box, Windows 98SE DOS box,
Windows 2000 DOS box, but for example not
in other DOSes like DR-DOS, where the value
varies on circumstances. No program should
rely on such random sideeffects of a
particular implementation.
old-format .EXE executables begin running with the following
register values:
AL = 00h if first FCB has no or a valid drive letter,
FFh if no valid drive letter
AH = 00h if second FCB has no or a valid drive letter,
FFh if no valid drive letter
DS,ES = PSP segment
SS:SP as defined in .EXE header
CS:IP points to entry point into program
Notes: .EXE-format programs without a stack segment are
treated differently depending on version;
under DOS 5.0+ if the obtained memory block
is larger or equal to 64 Kb the stack pointer
will not be touched, otherwise the pointer
will be initialized similar as for .COM-
format programs, that is, as long as the
program's memory requirements are less than
64 Kb 256 bytes stack will be added if
possible, otherwise SP is placed at the top
of the 64 Kb at FFFEh.
officially, BX,CX,DX,SI,DI,BP,Flags, as well as
the high register words on 386+ CPUs are
undefined and should not be relied upon in
programs
AL and AH are always 00h under both, DESQview
and RxDOS 6.0-7.1.6, while under DOS-C they
are always FFh (probably also under FreeDOS -
subject to change).
AX appears to be zero under MS-DOS/PC DOS
DEBUG, but the DR-DOS 7.xx DEBUG.EXE sets
up the AH and AL values according to the
results of the first and second FCB
tests, however, the results are different
from the values for INT 21h/AH=4Bh (00h for
no valid or default drive letter, 01h..1Ah
for A:..Z:, many other chars x: appear to
be returned with either +B0h, +40h, or
+20h added to the letter, for example 0:..9:
resulting in D0h..D9h???).
BX:CX holds the size of the program under RxDOS
6.0-7.1.6, similar to what usually happens
under other DOSes when loading a program in
DEBUG.EXE. Both registers are normally set
to 0000h under DOS-C and FreeDOS (BETA 7),
but if compiled as IPL, BX holds the boot
drive and CX the number of floppies.
DX,SI,DI,BP are all set to 0000h under RxDOS
6.0-7.1.6, DOS-C and FreeDOS but not under
operating systems of the MS-DOS/PC DOS or
DR-DOS families. These registers are set
to 0000h under DEBUG.EXE.
the Flags are set to 0000h under RxDOS
6.0-7.1.6, DOS-C, and FreeDOS, but not
under the other DOSes.
the stack can be pre-initialized.
BUG: some badly written utilities seem to rely on the
D-Flag being cleared on startup, a condition
that must not necessarily be true, so noone
should rely on this.
new executables begin running with the following register
values
AX = environment segment
BX = offset of command tail in environment segment
CX = size of automatic data segment (0000h = 64K)
ES,BP = 0000h
DS = automatic data segment
SS:SP = initial stack
the command tail corresponds to an old executable's PSP:0081h
and following, except that the 0Dh is turned into a NUL
(00h); new format executables have no PSP
under the FlashTek X-32 DOS extender, only function 00h is
supported and the pointers are passed in DS:EDX and ES:EBX
DR Concurrent DOS 386 (since 1988-07-08) will load EXEPACKed
programs above the 64K mark, that is, outside "lowest
memory", by extending the memory block containing the
program's environment (even larger than 32 Kb???).
DR DOS 5.0+ always loads .EXE-format programs with no fixups,
and (since 1990-05-25) also .COM-format programs compressed
with SpaceMaker - and therefore starting with 9Ch 55h
(PUSHF/PUSH BP) - above the 64K mark to avoid the EXEPACK
wrap around bug. It does this by extending the memory block
containing the program's environment, since 1989-12-14 it
will even allocate multiple fillers when necessary.
This environment expansion code is disabled if the name
of the parent program as stored in the MCB is "WIN" to
improve performance when WIN.COM starts KERNEL.EXE
(0 relocation items).
DR DOS 3.41 and 5.0 check for a valid filename before testing
the subfunction number, so the otherwise invalid subfunction
02h will only return error code 01h if the given filename
actually exists; otherwise, errors 02h, 03h, or 05h are
returned. This was corrected on 1990-10-02 for DR DOS 6.0+,
which range checks the subfunction before checking the
filename now.
the MS-DOS/PC DOS 5.0+??? kernel scans for a variety of code
sequences in .EXE format executables and applies patches
for various versions of EXEPACKed files in order to let
them run in lowest memory (when DOS is in the HMA), that
is, a load segment < 64 Kb. Otherwise they would display
"Packed file corrupt".
The code checks that the code's entry point ("IP") is not
< 0002h (it was 0012h in the observed files) and then reads
the WORD immediately preceeding the entry point (that is,
0010h here). If this WORD reads 5242h ("RB"), the file is
assumed to be EXEPACKed. The code then looks for one of
several combinations of code sequences at offsets from
this "RB" signature.
the MS-DOS 5.0+??? kernel scans for an unknown class of .COM
executables. If their signatures are found in the file, the
A20 countdown variable at offset 18h in the disk buffer info
table (see Table "DOS 5.0-6.0 disk buffer info") will
be set to 10, which will cause A20 to be disabled after
INT 21h calls for this count of INT 21h calls to follow.
Presumably this class of programs requires A20 to be disabled
for some time after it begins execution. (Similar actions
occur on entry into INT 21h/AH=25h and AH=49h.)
BUGS: DOS 2.00 assumes that DS points at the current program's PSP
Load Overlay (subfunction 03h) loads up to 512 bytes too many
if the file contains additional data after the actual overlay
Load but Do Not Execute (subfunction 01h) is reported to
corrupt the top word of the caller's stack if the loaded
module terminates with INT 21/AH=4Ch in some versions of
MS-DOS, including v5.00.
according to Rational Systems, MS-DOS/PC DOS 5.0+ searches
executables for a number of opcode sequences which indicate
various older issues of the Rational DOS Extender before
version 3.95; if found, the kernel will apply assorted
patches for 286 and 386 CPUs to the loaded program image:
the 286 patch fixes the trashing of the CX register in a
certain loop; it will by applied by DOS 5.0+ on 286 CPUs
only when the kernel is relocated into the HMA. The patch
itself resides statically in the DOS data segment.
on 386er CPUs, DOS 6.0+ overwrites parts of the Extender's
unused code for 286 CPUs or the code dealing with
NEC 98xx's with several version dependent patches fixing
the trashing of the high word of EAX (if not DPMI or VCPI)
and the high words of EAX,EBX,ECX,EDX,ESI (if VCPI),
but forgets to fix the trashing of the high word of ESP and
the corruption of the FS and GS registers, which can occur
during interrupt processing.
Lotus 1-2-3 version 3.x+??? is one of the applications using
buggy versions of the Rational System DOS extender.
SeeAlso: AX=4B05h,AH=4Ch,AH=4Dh,AH=64h/BX=0025h,AH=8Ah,INT 2E,
INT 60/DI=0604h

Format of EXEC parameter block for AL=00h,01h,04h:
Offset Size Description (Table 01590)
00h WORD segment of environment to copy for child process (copy
caller's environment if 0000h)
02h DWORD pointer to command tail to be copied into child's PSP
at 80h (See Table "command tail" at INT 21h/AH=26h)
06h DWORD pointer to first FCB to be copied into child's PSP
at 5Ch
0Ah DWORD pointer to second FCB to be copied into child's PSP
at 6Ch
0Eh DWORD (AL=01h) will hold subprogram's initial SS:SP on return
12h DWORD (AL=01h) will hold entry point (CS:IP) on return
Notes: PTS-DOS 6.51 will allocate the environment above the program
when the INSTALL[HIGH] /E load option was used (SeeAlso:
INT 21h/AH=58h).
early versions of DR Concurrent DOS and DOS Plus did not cope
with an environment value of zero; this was fixed on
1988-06-02 for the [D]CONFIG.SYS INSTALL= directive,
apparently introduced around this date in Concurrent DOS???
(This directive showed up in the single-user series not
before a year later with DR DOS 3.41+???)
if the environment segment supplied is zero and the caller also
has a zero environment, DOS will not allocate an environment
at all.
DR DOS 5.0+ (since 1990-04-10), RxDOS 6.0+ (at least since
1994-06-06), and DOS-C (1996) are known to handle this
special case as well.
MS-DOS/PC DOS/DR-DOS, and DOS-C (1996) verifies that the actual
environment is at most 32768 bytes long and is
zero-terminated, if it is not, the kernel will bail out.
in order to reduce memory fragmentation and save memory, future
issues of DR-DOS (post 7.05) may possibly add new load
options like

[HI]INSTALL|INSTALL[HIGH] and LH|LOADHIGH|HILOAD
[/D[:d[:]]] [/E] [/L...] [/S] [/Z] = d:\path\prg.com params,

where:

/D starts the program from a temporary SUBSTed drive
(default B:)
/E places the environment above the program instead
of below
/Z creates a zero-environment (similar to DESQview's
feature)

RxDOS 6.0 is known to handle the case of a zero command tail
pointer, in which case it will not copy a command tail into
the PSP.
DOS-C (1996) will truncate the command tail copied into the PSP
so it never exceeds 127 characters and it will always
terminate it with a 0Dh (CR).
SeeAlso: #01591,#01592

If you find errors or omissions, please let me know.

Greetings,

Matthias

--
<mailto:Matthi...@post.rwth-aachen.de>; <mailto:mp...@drdos.org>
http://www.uni-bonn.de/~uzs180/mpdokeng.html; http://mpaul.drdos.org

"Programs are poems for computers."


Reply all
Reply to author
Forward
0 new messages