UMBC CMSC 211 |
For the parent to start another program, it is necessary to use the DOS EXEC function. The child is loaded into memory above the parent and is executed until it terminates, when control is returned to the parent, which has been doing nothing, just waiting for the child to finish.
To call the EXEC function, you must set up the registers with the following parameters:
AH | 4Bh |
AL | 0 |
DS:DX | the address of the null-terminated name of the child program. It must have the full pathname and extension. The PATH variable is not used to find the file! The DOS file COMMAND.COM can search the PATH and execute .BAT files. |
ES:BX | is the address of a 7-word parameter block |
Offset | Size | Description |
---|---|---|
00h | 2 | segment pointer to environment (if 0, use the same block as the parent). Must be paragraph aligned and consist of a sequence of ASCIIZ strings, |
02h | 4 | pointer to the command-tail line. Contains a byte count (which does not include the carriage return at the end). The first character in the string must be a blank. |
06h | 4 | pointer to the first FCB to be copied into the new PSP (author says FCBs are not used and you can use -1 |
0Ah | 4 | pointer to the second FCB |
Before using this function, you must ensure that there is enough unallocated memory available for the child process. If necessary, you must release all the memory to load the child process. If you don't, you will get an out of memory error.
The word at 02h in the PSP is the segment address of the next memory location available for allocation, and normally that will be A000h, which is all of available memory is allocated to the expectant parent and no memory is available for the child program.
Use the realloc DOS call to modify the amount of memory allocation. We set it up with the following parameters:
AH | 4Ah |
BX | new memory size in paragraphs |
ES | segment of block address |
07h | damaged memory control block |
08h | insufficient memory |
09h | incorrect memory block addres |
The William Jones gives the following about how to change the allocation:
Remember the parent just sits there, not doing a thing, until the child is finished. When returning from the EXEC call, the Carry Flag will be clear if everything went Oill be clear if everything went OK. However, the EXEC call only saved the CS register. The SS and SP registers will be clobbered, and the only thing the parent knows about when it returns, so the parent must save the SS and SP values in the .CODE segment! Then when the parent starts back up, it must restore the SS and SP values before it does anything else.
Let's look at an example of how to do this.
INCLUDE PCMAC.INC .MODEL SMALL ASSUME SS:NOTHING STACKSIZE EQU 100h .STACK STACKSIZE PSP SEGMENT AT 0-256 ORG 2cH EnvirSeg DW ? PSP ENDS .DATA CmdFile DB 'cmdtail.exe', CmdTail DB 17, ' the command tail ',13 ParmBlock DW ? DD CmdTail DD -1, -1; ; Null FCBs .CODE EXTRN CCheck : NEAR SaveSS DW ? ; This is different, SaveSP DW ? ; must be in code segment! execer PROC mov ax, @data mov ds, ax ASSUME es:PSP mov ax, EnvirSeg ; Get the string of environment ; variables from the parent mov ParmBlock ; ; Figure out how much memory to keep and then release the ; memory that is extra. ; SS + (stacksize + 15) / 16 - ES : What we have to do is adjust the address up to the start ; of the next memory paragraph. ; mov bx, ss; ; Paragraph of last segment add bx, (STACKSIZE+15)/16; since this is all known ; at assembly time, this is ; reduced to a simple constant ; by the assembler mov ax, es ; can't do math with the ES register sub bx, ax ; bx has the program size now mov ah, 4Ah ; REALLOC function int 21 call CCheck ; Abort if memory could not be released mov SaveSP, sp mov SaveSS, ss push ds pop es ASSUME es:@data mov dx, OFFSET CmdFile ; ds:dx --> file to EXEC mov bx, OFFSET ParmBlock ; es:bx --> parameter block mov ax, 4B00h int 21 ASSUME ds:NOTHING, es:NOTHING ; cli ; Don't let an interrupt occur ; until the stack is restored or ; everything is lost! ; mov ss, SaveSS ; mov instruction does not change mov sp, SaveSP ; the flags! sti ; Turn the interrupts back on ; as soon as possible! ; ; Stack is now restored and the carry flag from the interrupt is in ; the flag register ; call CCheck _Exit 0 execer ENDP END execer