I write EXE program with SMALL model.
I want to load other programs with the help of my program. I read that first of all I must free s
You don't need to free memory in an .exe
program. Only a .com
program reserves all memory. It's rather complicated to determine the real last byte of an .exe
program and to find the segment of the allocated block. BTW: In a .com
program you must adjust the stack pointer!
As @RossRidge mentions, some linkers (e.g. TLINK) write into the header an information to allocate the maximum memory. This is annoying.
You can modify this header item by using a tool like Microsoft's exemod
which is contained in the MASM suites (versions < 6). A suite is downloadable here. The exemod utility can be found in DISK4. Use it like:
exemod <exefile> /max 1
Another option is to resize the allocated memory inside the program. Make first a simple program HELLO.EXE
to be executed by a parent program:
.MODEL small
.STACK ; default: 1000h
.DATA
hello db "Hello world", 13, 10, "$"
.CODE
main PROC
mov ax, @data
mov ds, ax
mov dx, OFFSET hello
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
main ENDP
END main
Now the parent:
.MODEL small
.STACK
.DATA
hello db "HELLO.EXE", 0
params label word
dw 0
dw OFFSET command_line, SEG command_line
dw 0ffffh,0ffffh ; fcb1
dw 0ffffh,0ffffh ; fcb2
command_line db 0,13
.CODE
free_memory PROC
mov ax, sp ; SS:SP -> nearly the end of program
shr ax, 4
mov bx, ss
add bx, ax
add bx, 2 ; BX = a paragraph beyond program
mov ax, es ; ES -> first paragraph of the program (containing PSP)
sub bx, ax ; BX = program size in paragraphs
mov ah, 4ah ; Resize memory block - http://www.ctyme.com/intr/rb-2936.htm
int 21h ; Call MS-DOS
ret
free_memory ENDP
execute_hello PROC
push ds ; Save DS
push es ; Save ES
mov cs:[stk_seg],ss ; Save stack pointer
mov cs:[stk_ptr],sp
mov ax, 4B00h
mov dx, OFFSET hello
mov bx, SEG params
mov es, bx
mov bx, OFFSET params
mov ax,4b00h ; Exec - load and/or execute program - http://www.ctyme.com/intr/rb-2939.htm
int 21h ; Call MS-DOS
cli ; Let no interrupt disturb
mov ss,cs:[stk_seg] ; Restore stack pointer
mov sp,cs:[stk_ptr]
sti ; Allow interrupts
pop es ; Restore ES and DS
pop ds
ret
; Data for this function in the code segment
stk_ptr dw 0
stk_seg dw 0
execute_hello ENDP
main PROC
mov ax, @data ; Initialize DS
mov ds, ax
call free_memory ; ES should point to PSP (default)
call execute_hello
mov ax, 4C00h ; Terminate with return code - http://www.ctyme.com/intr/rb-2974.htm
int 21h ; Call MS-DOS
main ENDP
END main
The end of the program is determined by the stack pointer. You should therefore be sure that the STACK segment is the last segment in the program. Generate a .MAP
file with the tlink command line option /s
. It should look like:
Start Stop Length Name Class
00000H 0005BH 0005CH _TEXT CODE
00060H 00079H 0001AH _DATA DATA
00080H 0047FH 00400H STACK STACK
Detailed map of segments
0000:0000 005C C=CODE S=_TEXT G=(none) M=INBBC8~1.ASM ACBP=48
0006:0000 001A C=DATA S=_DATA G=DGROUP M=INBBC8~1.ASM ACBP=48
0006:0020 0400 C=STACK S=STACK G=DGROUP M=INBBC8~1.ASM ACBP=74
Program entry point at 0000:004C
As you can see STACK
is the last segment listed here.
Now you can run the parent and read what the child (HELLO.EXE) has to tell :-)