Art of Assembly/Win32 Edition is now available. Let me read that version.
PLEASE: Before emailing me asking how to get a hard copy of this text, read this.
Important Notice: As you have probably discovered by now, I am no longer updating this document. The reason is quite simple: I'm working on a Windows version of "The Art of Assembly Language Programming". In the past I have encouraged individuals to send me corrections to this text. However, as I am no longer updating this material, don't expect those correctioins to appear in a future release. I am collecting errata that I will post to Webster someday, so feel free to continue sending corrections to AoA/DOS (16-bit) to rhyde@cs.ucr.edu. If you're more interested in leading edge material, please see the information about the Win/32 edition, above.
Function # (AH) |
Input Parameters |
Output Parameters |
Description |
---|---|---|---|
4Bh | al - 0ds:dx - pointer to program name.es:bx - pointer to LOADEXEC structure. |
ax - error code if carry set. |
Load and execute program |
4Bh | al - 1ds:dx - pointer to program name.es:bx - pointer to LOAD structure. |
ax - error code if carry set. |
Load program |
4Bh | al - 3ds:dx - pointer to program name.es:bx - pointer to OVERLAY structure. |
ax - error code if carry set. |
Load overlay |
4Ch | al - process return code |
Terminate execution | |
4Dh | al - return valueah - termination method. |
Get child process return value |
es:bx
, is a pointer to a LOADEXEC data structure. This data structure takes the following form:
LOADEXEC struct EnvPtr word ? ;Pointer to environment area CmdLinePtr dword ? ;Pointer to command line FCB1 dword ? ;Pointer to default FCB1 FCB2 dword ? ;Pointer to default FCB2 LOADEXEC ends
Envptr
is the segment address of the DOS environment block created for the new application. If this field contains a zero, DOS creates a copy of the current process' environment block for the child process. If the program you are running does not access the environment block, you can save several hundred bytes to a few kilobytes by pointing the environment pointer field to a string of four zeros.
The CmdLinePtr
field contains the address of the command line to supply to the program. DOS will copy this command line to offset 80h in the new PSP it creates for the child process. A valid command line consists of a byte containing a character count, a least one space, any character belonging to the command line, and a terminating carriage return character (0Dh). The first byte should contain the length of the ASCII characters in the command line, not including the carriage return. If this byte contains zero, then the second byte of the command line should be the carriage return, not a space. Example:
MyCmdLine byte 12, " file1 file2",cr
The FCB1
and FCB2
fields need to point at the two default file control blocks for this program. FCBs became obsolete with DOS 2.0, but Microsoft has kept FCBs around for compatibility anyway. For most programs you can point both of these fields at the following string of bytes:
DfltFCB byte 3," ",0,0,0,0,0
The load and execute call will fail if there is insufficient memory to load the child process. When you create an ".EXE" file using MASM, it creates an executable file that grabs all available memory, by default. Therefore, there will be no memory available for the child process and DOS will always return an error. Therefore, you must readjust the memory allocation for the parent process before attempting to run the child process.
There are other possible errors as well. For example, DOS might not be able to locate the program name you specify with the zero terminated string. Or, perhaps, there are too many open files and DOS doesn't have a free buffer available for the file I/O. If an error occurs, DOS returns with the carry flag set and an appropriate error code in the ax
register. The following example program executes the "COMMAND.COM" program, allowing a user to execute DOS commands from inside your application. When the user types "exit" at the DOS command line, DOS returns control to your program.
; RUNDOS.ASM - Demonstrates how to invoke a copy of the COMMAND.COM ; DOS command line interpreter from your programs. include stdlib.a includelib stdlib.lib dseg segment para public 'data' ; MS-DOS EXEC structure. ExecStruct word 0 ;Use parent's Environment blk. dword CmdLine ;For the cmd ln parms. dword DfltFCB dword DfltFCB DfltFCB byte 3," ",0,0,0,0,0 CmdLine byte 0, 0dh ;Cmd line for program. PgmName dword filename ;Points at pgm name. filename byte "c:\command.com",0 dseg ends cseg segment para public 'code' assume cs:cseg, ds:dseg Main proc mov ax, dseg ;Get ptr to vars segment mov ds, ax MemInit ;Start the memory mgr. ; Okay, we've built the MS-DOS execute structure and the necessary ; command line, now let's see about running the program. ; The first step is to free up all the memory that this program ; isn't using. That would be everything from zzzzzzseg on. ; ; Note: unlike some previous examples in other chapters, it is okay ; to call Standard Library routines in this program after freeing ; up memory. The difference here is that the Standard Library ; routines are loaded early in memory and we haven't free up the ; storage they are sitting in. mov ah, 62h ;Get our PSP value int 21h mov es, bx mov ax, zzzzzzseg ;Compute size of sub ax, bx ; resident run code. mov bx, ax mov ah, 4ah ;Release unused memory. int 21h ; Tell the user what is going on: print byte cr,lf byte "RUNDOS- Executing a copy of command.com",cr,lf byte "Type 'EXIT' to return control to RUN.ASM",cr,lf byte 0 ; Warning! No Standard Library calls after this point. We've just ; released the memory that they're sitting in. So the program load ; we're about to do will wipe out the Standard Library code. mov bx, seg ExecStruct mov es, bx mov bx, offset ExecStruct ;Ptr to program record. lds dx, PgmName mov ax, 4b00h ;Exec pgm int 21h ; In MS-DOS 6.0 the following code isn't required. But in various older ; versions of MS-DOS, the stack is messed up at this point. Just to be ; safe, let's reset the stack pointer to a decent place in memory. ; ; Note that this code preserves the carry flag and the value in the ; AX register so we can test for a DOS error condition when we are done ; fixing the stack. mov bx, sseg mov ss, ax mov sp, offset EndStk mov bx, seg dseg mov ds, bx ; Test for a DOS error: jnc GoodCommand print byte "DOS error #",0 puti print byte " while attempting to run COMMAND.COM",cr,lf byte 0 jmp Quit ; Print a welcome back message. GoodCommand: print byte "Welcome back to RUNDOS. Hope you had fun.",cr,lf byte "Now returning to MS-DOS' version of COMMAND.COM." byte cr,lf,lf,0 ; Return control to MS-DOS Quit: ExitPgm Main endp cseg ends sseg segment para stack 'stack' dw 128 dup (0) sseg ends zzzzzzseg segment para public 'zzzzzzseg' Heap db 200h dup (?) zzzzzzseg ends end Main
LOAD struct EnvPtr word ? ;Pointer to environment area. CmdLinePtr dword ? ;Pointer to command line. FCB1 dword ? ;Pointer to default FCB1. FCB2 dword ? ;Pointer to default FCB2. SSSP dword ? ;SS:SP value for child process. CSIP dword ? ;Initial program starting point. LOAD ends
The LOAD command is useful for many purposes. Of course, this function provides the primary vehicle for creating semiresident programs; however, it is also quite useful for providing extra error recovery, redirecting application I/O, and loading several executable processes into memory for concurrent execution.
After you load a program using the DOS load command, you can obtain the PSP address for that program by issuing the DOS get PSP address call. This would allow the parent process to modify any values appearing in the child process' PSP prior to its execution. DOS stores the termination address for a procedure in the PSP. This termination address normally appears in the double word at offset 10h in the PSP. If you do not change this location, the program will return to the first instruction beyond the int 21h instruction for the load function. Therefore, before actually transferring control to the user application, you should change this termination address.
ds:dx
register pair and the address of a data structure in the es:bx
register pair. This overlay data structure has the following format:
overlay struct StartSeg word ? RelocFactor word 0 overlay ends
The StartSeg
field contains the segment address where you want DOS to load the program. The RelocFactor
field contains a relocation factor. This value should be zero unless you want the starting offset of the segment to be something other than zero.
ExitPgm
macro executes this command). In this section we'll look at exactly what the terminate process function call does.Unless you really know what you're doing, you should not change the values at offsets 0Ah, 0Eh, or 12h in the PSP. By doing so you could produce an inconsistent system when your program terminates.
al
register at the point of termination plus information that tells you how the child process terminated.ah
=4Dh) returns the termination code in the al register. It also returns the cause of termination in the ah register. The ah
register will contain one of the following values:Value in AH | Reason for Termination |
---|---|
0 | Normal termination (int 21h, ah=4Ch) |
1 | Terminated by ctrl-C |
2 | Terminated by critical error |
3 | TSR termination (int 21h, ah=31h) |
al
is valid only for normal and TSR terminations.