• Please review our updated Terms and Rules here

Allocating RAM with int 21h- A guide to MZ gotchas

cr1901

Veteran Member
Joined
Dec 28, 2011
Messages
817
Location
NJ
Mike,

When any program in DOS gets control, it has all of memory allocated to it. You need to free the memory beyond the end of your program with INT 21h/AH=4Ah, before you can allocate anything more (other than from UMBs) with INT 21/AH=48h.

Code:
	mov	segPSP,es		; Save segment of PSP

    ....

; Free extra memory
	mov	ax,ds			; Segment of DGROUP
	lea	bx,ZTAIL+@STKSIZE+15	; Size of DGROUP, rounded up to para
        shr	bx,(4-0)		; Convert from BYTEs to PARAs
	add	bx,ax			; Segment address of end of program
	sub	bx,segPSP		; Total size of program in paras
	mov	es,segPSP		; Segment of block to modify
	assume	es:nothing
	DOSCALL @MODMEM		; Modify memory block ES to BX paras

    ...

	public	ZTAIL
ZTAIL	 label	byte


Here is the DOS call running in SYMDEB. Works as expected.

Code:
Processor is [80286]
-
-a
0F8A:0100 mov ah,48
0F8A:0102 mov bx,1000
0F8A:0105 int 21
0F8A:0107 nop
0F8A:0108
-p
AX=4800  BX=0000  CX=0000  DX=0000  SP=EF65  BP=0000  SI=0000  DI=0000
DS=0F8A  ES=0F8A  SS=0F8A  CS=0F8A  IP=0102   NV UP EI PL NZ NA PO NC
0F8A:0102 BB0010         MOV    BX,1000
-p
AX=4800  BX=1000  CX=0000  DX=0000  SP=EF65  BP=0000  SI=0000  DI=0000
DS=0F8A  ES=0F8A  SS=0F8A  CS=0F8A  IP=0105   NV UP EI PL NZ NA PO NC
0F8A:0105 CD21           INT    21  ;Allocate Memory
-p
AX=0F8A  BX=1000  CX=0000  DX=0000  SP=EF65  BP=0000  SI=0000  DI=0000
DS=0F8A  ES=0F8A  SS=0F8A  CS=0F8A  IP=0107   NV UP EI PL NZ NA PO NC
0F8A:0107 90             NOP
-

As far as calling a C OBJ to allocate memory for you in another program, that's a bigger can of worms, because you need to get the C runtime initialized. If you want to call C runtime functions from assembly code, I can send you examples of how to do that.

/Bill

I have a need to allocate memory using DOS, not knowing ahead of time whether I will have enough free memory for a set of dynamically-sized data structures that should ideally, be stored sequentially, and allowed to grow/shrink without overwriting one another!

DOS by default will try to allocate as much memory as is suggested in an MZ's EXE header. In some references, the field is called MAXALLOC. By default, most linkers will assign MAXALLOC the highest possible value of 65535 paragraphs (about 1MB- this of course will never happen in practice). Therefore, barring memory fragmentation, even small memory allocations will likely fail. One solution is to immediately free as much memory as possible (keeping enough space for your uninitialized vars), using INT 21h/AH=4Ah.

From taking a peek at OpenWatcom's source code, this is exactly what the DOS C Runtime does. According to the MZ header for WLINK, up to 65535 paragraphs can be allocated to MZ EXEs generated with WLINK. The C runtime code ($WATCOM\src\startup\dos\cstrt086.asm) will then run INT 21h/AH=4Ah to free the memory that's not actually currently in use by the program, so that future malloc()s or INT 21h/AH=48h calls will succeed.


Nope. I can change the amount to 1000h and I get the following:

Code:
DOS function 48H returns 0e88

Try it yourself. (Hint: It's a matter of knowing the standard Microsoft toolset.. Look at page 974 in the big gray DOS Encyclopedia.)

Chuck(G) proposes an alternative method that doesn't require a deallocation-reallocation dance... modify the MZ header directly using EXEMOD (presumably that's what's on page 974) or some simple C program to modify the MAXALLOC field directly! Presumably, I should set MAXALLOC equal to the MINALLOC field. This also saves space in the EXE itself and saves me time from having to write such deallocation myself, which I'm sure I would screw up somehow.

Just two things:
  • Why don't OMF Linkers (even WLINK) give the user the option to override MAXALLOC.
  • Is DOS smart enough to know to free the allocated memory- specifically the memory which was NOT allocated on load- automatically on program termination? EDIT: No! See this DDJ entry:
    DDJ said:
    Any other memory allocated by an application using these functions must subsequently be freed or it will remain in memory.
 
Back
Top