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.