In MS-DOS version 2, the EXEC function destroys the contents of all registers except the code segment (CS) and instruction pointer (IP). Therefore, before making the EXEC call, the parent program must push the contents of any other registers that are important onto the stack and then save the stack segment (SS) and stack pointer (SP) registers in variables. Upon return from a successful EXEC call (that is, the child program has finished executing), the parent program should reload SS and SP from the variables where they were saved and then pop the other saved registers off the stack. In MS-DOS versions 3.0 and later, the stack and other registers are preserved across the EXEC call in the usual fashion.
Finally, the parent can use Int 21H Function 4DH to obtain the termination type and return code of the child program.
The EXEC function will fail under the following conditions:
Not enough unallocated memory is available to load and execute the requested program file.
The requested program can't be found on the disk.
The transient portion of COMMAND.COM in highest RAM (which contains the actual loader) has been destroyed and not enough free memory is available to reload it (PC-DOS version 2 only).
Figure 12-1 summarizes the calling convention for function 4BH. Figure 12-2 shows a skeleton of a typical EXEC call. This particular example uses the EXEC function to load and run the MS-DOS utility CHKDSK.COM. The SHELL.ASM program listing later in this chapter (Figure 12-5) presents a more complete example that includes the use of Int 21H Function 4AH to free unneeded memory.
Called with:
AH = 4BH AL = function type 00 = load and execute program 03 = load overlay ES:BX = segment:offset of parameter block DS:DX = segment:offset of program specification
Returns:
If call succeeded
Carry flag clear. In MS-DOS version 2, all registers except for CS:IP may be destroyed. In MS-DOS versions 3.0 and later, registers are preserved in the usual fashion.
If call failed
Carry flag set and AX = error code.
Parameter block format:
If AL = 0 (load and execute program)
Bytes 0—1 = segment pointer, environment block
Bytes 2—3 = offset of command-line tail
Bytes 4—5 = segment of command-line tail
Bytes 6—7 = offset of first file control block to be copied
into new PSP + 5CH
Bytes 8—9 = segment of first file control block
Bytes 10—11 = offset of second file control block to be copied
into new PSP + 6CH
Bytes 12—13 = segment of second file control block
If AL = 3 (load overlay)
Bytes 0—1 = segment address where file will be loaded
Bytes 2—3 = relocation factor to apply to loaded image
Figure 12-1. Calling convention for the EXEC function (Int 21H Function 4BH).
cr egu 0dh ; ASCII carriage return
.
.
.
mov stkseg,ss ; save stack pointer
mov stkptr,sp
mov dx,offset pname ; DS:DX = program name
mov bx,offset pars ; ES:BX = param block
mov ax,4b00h ; function 4bh, subfunction 00h
int 21h ; transfer to MS-DOS
mov ax,_DATA ; make our data segment
mov ds,ax ; addressable again
mov es,ax
cli ; (for bug in some 8088s)
mov ss,stkseg ; restore stack pointer
mov sp,stkptr
sti ; (for bug in some 8088s)
jc error ; jump if EXEC failed
.
.
.
stkseg dw 0 ; original SS contents
stkptr dw 0 ; original SP contents
pname db '\CHKDSK.COM',0 ; pathname of child program
pars dw envir ; environment segment
dd cmdline ; command line for child
dd fcb1 ; file control block #1
dd fcb2 ; file control block #2
cmdline db 4,' *.*',cr ; command line for child
fcb1 db 0 ; file control block #1
db 11 dup ('?')
db 25 dup (0)
fcb2 db 0 ; file control block #2
db 11 dup (' ')
db 25 dup (0)
envir segment para 'ENVIR' ; environment segment
db 'PATH=',0 ; empty search path
; location of COMMAND.COM
db 'COMSPEC=A:\COMMAND.COM',0
db 0 ; end of environment
envir ends
Figure 12-2. A brief example of the use of the MS-DOS EXEC call, with all necessary variables and command blocks. Note the protection of the registers for MS-DOS version 2 and the masking of interrupts during loading of SS:SP to circumvent a bug in some early 8088 CPUs.