News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

allocating memory on-the-fly

Started by lianergoist, December 12, 2006, 07:51:49 AM

Previous topic - Next topic

lianergoist

Hi

I am new to assembly, but do know the basic stuff. I would like to know how I can allocate memory "on-the-fly" like I do with malloc in C (the first 640 KB is fine).

I know how I can set aside memory with BUFFER DB 64000 DUP(?), but it may be more or less than what I need. Is it possible to allocate  memory on-the-fly?

Thomas

MichaelW

Hi Thomas,

Yes it is possible. Take a look at Interrupt 21h, functions 48h (Allocate Memory), 49h (Free Allocated Memory), and 4Ah (Set Memory Block Size). And for more control, function 5800h (Get Allocation Strategy) and 5801h (Set Allocation Strategy). If you do not already have a reference, search this forum for a link to Ralf Brown's Interrupt List.

BTW, the loader normally allocates all or most of the available memory to a program, so prior to allocating memory you must determine the actual size of the program and use function 4Ah to shrink the program's allocation. You could use the memory as initially allocated, but to do so you would still need to determine the actual size of the program, determine where the end of the allocated memory is, and calculate the segment address of the memory, so you really would not gain anything. Refer to recent posts (IIRC) in this forum for example code.
eschew obfuscation

dncprogrammer

What about calculating available memory with out DOS functions?
jon

lianergoist

Quote
Yes it is possible. Take a look at Interrupt 21h, functions 48h (Allocate Memory), 49h (Free Allocated Memory), and 4Ah (Set Memory Block Size). And for more control, function 5800h (Get Allocation Strategy) and 5801h (Set Allocation Strategy). If you do not already have a reference, search this forum for a link to Ralf Brown's Interrupt List.

Thank you. I have read about these functions, but thought it had something to do with loading programs... I am trying to learn myself asm from the book "IBM PC assembly langguage and programming" by Peter Abel, and I must say, I think he makes things more complicated than he have to...

Quote
BTW, the loader normally allocates all or most of the available memory to a program, so prior to allocating memory you must determine the actual size of the program and use function 4Ah to shrink the program's allocation.

I am not usre I know how to determine the actual size of my program, but I will look into it. If I give up, I will reurn here and cry for help... :-)

Quote
You could use the memory as initially allocated, but to do so you would still need to determine the actual size of the program, determine where the end of the allocated memory is, and calculate the segment address of the memory, so you really would not gain anything. Refer to recent posts (IIRC) in this forum for example code.

I have not been able to find examples. I did find another post talking about functions 48h etc. but no examples. If you think you can come up with one, fell free to post it. Else, I think you have been very helpfull, and I will try to figure it out from here.

Thanks...

Thomas

MichaelW

Quote from: dncprogrammer on December 12, 2006, 02:43:14 PM
What about calculating available memory with out DOS functions?
Well, you could get the size of your program's memory block from the memory control block that precedes the PSP, and by subtracting the size of the program you could determine how much memory was available above the program. The problem here is that this is an undocumented method that would have, at best, only a small code size advantage over the documented, reliable method.
eschew obfuscation

dncprogrammer

Michael, thank you as usual,
How reliable is the value returned by INT12h, I mean, if one wanted to actually sense the real amount of total memory could it be done in a timely fashion through a looping program or is there a more traditional approach? Same question for extended memory.

jon

MichaelW

#6
The value returned by Interrupt 12h was probably reliable in the beginning, but when memory managers arrived on the scene, it became common for them to hook Interrupt 12h and return a smaller, fake value. On recent systems Interrupt 12h is fairly useless because it returns the kilobytes of contiguous memory as a 16-bit value, which limits it to 64MB. There are other methods, and the attachment demonstrates one of them, but note that it will not work under Windows 2000/XP.

Assuming there were no memory managers ( EMM386, etc, or Windows) running, you should be able to determine the actual amount of memory by probing, but to do it reliably I think you would need to write to the memory.



[attachment deleted by admin]
eschew obfuscation

MichaelW

Thomas,

The topic I was remembering is here, and the post of interest is here
eschew obfuscation

lianergoist

Quote from: MichaelW on December 13, 2006, 04:28:27 AM
The topic I was remembering is here, and the post of interest is here

Thank you. I have been playing with it, and now I have something that assemble and seems to be working. But that could be pure luck! Please look at the following code and tell me if this is the correct approach. I am not sure it is correct to load the address of buffer to DI in function 49h, but... I can't load it to ES, so I guess DI is what I am supposed to use.

Thanks...

Thomas



TITLE mem.asm
.MODEL SMALL
.STACK 4096
.DATA?
buffer DW ?
buffer2 DB 20 DUP(?)
filehandle DW ?
.DATA
filename DB 'test.txt',0
allocfail_msg DB 'Allocation failed',0Dh,0Ah,'$'
freefail_msg DB 'Freeing memory failed',0Dh,0Ah,'$'
openfail_msg DB 'Opening file failed',0Dh,0Ah,'$'
readfail_msg DB 'Reading file failed',0Dh,0Ah,'$'
; ----------------------------------------------------
.CODE
MAIN PROC   FAR
MOV    AX,@data ;
MOV    DS,AX ;

mov bx,es ;Copy the first address memory into bx
mov ax,ss ;Copy address of ss into ax
sub ax,bx ;
mov cx,sp ;convert SP to paragraph "units"
shr cx,4 ;
inc cx ;
add ax,cx ;<- and then add here

mov bx,ax    ;
mov ah,4Ah ;Release unused memory
int 21h ;

mov ah,48h ;
mov bx,64 ;64 paragraphs = 1024 bytes
int 21h ;
jc allocfail ;
mov buffer,ax ;

mov ah,3dh ;open file
lea dx,filename ;
int 21h ;
jc openfail ;
mov filehandle,ax ;

mov ah,3fh ;read file
mov bx,filehandle ;
mov cx,10 ;10 bytes
lea dx,buffer ;into allocated memory
int 21h ;
jc readfail ;

mov ah,3eh ;
mov bx,filehandle ;
int 21h ;
jc closefail ;

mov ah,02h ;print on screen
mov cx,10 ;
lea di,buffer ;
L10: mov dl,[di] ;
int 21h ;
inc di ;
loop L10 ;
;jmp finish ;

mov ah,49h ;
lea di,buffer ; ???
int 21h ;
jnc finish ;

mov ah,09
lea dx,freefail_msg
int 21h

readfail:
openfail:
freefail:
allocfail:
finish:
MOV AH,10H ;Request keyboard
INT 16H ;  input

MOV AX,4C00H ;End of processing
INT 21H
MAIN ENDP
END MAIN



japheth




Quote from: lianergoist on December 13, 2006, 02:51:59 PM
Quote from: MichaelW on December 13, 2006, 04:28:27 AM
The topic I was remembering is here, and the post of interest is here

Thank you. I have been playing with it, and now I have something that assemble and seems to be working. But that could be pure luck! Please look at the following code and tell me if this is the correct approach. I am not sure it is correct to load the address of buffer to DI in function 49h, but... I can't load it to ES, so I guess DI is what I am supposed to use.

Thanks...

Thomas



TITLE mem.asm
.MODEL SMALL
.STACK 4096
.DATA?
buffer DW ?
buffer2 DB 20 DUP(?)
filehandle DW ?
.DATA
filename DB 'test.txt',0
allocfail_msg DB 'Allocation failed',0Dh,0Ah,'$'
freefail_msg DB 'Freeing memory failed',0Dh,0Ah,'$'
openfail_msg DB 'Opening file failed',0Dh,0Ah,'$'
readfail_msg DB 'Reading file failed',0Dh,0Ah,'$'
; ----------------------------------------------------
.CODE
MAIN PROC   FAR
MOV    AX,@data ;
MOV    DS,AX ;

mov bx,es ;Copy the first address memory into bx
mov ax,ss ;Copy address of ss into ax
sub ax,bx ;
mov cx,sp ;convert SP to paragraph "units"
shr cx,4 ;
inc cx ;
add ax,cx ;<- and then add here

mov bx,ax    ;
mov ah,4Ah ;Release unused memory
int 21h ;

mov ah,48h ;
mov bx,64 ;64 paragraphs = 1024 bytes
int 21h ;
jc allocfail ;
mov buffer,ax ;

mov ah,3dh ;open file
lea dx,filename ;
int 21h ;
jc openfail ;
mov filehandle,ax ;

mov ah,3fh ;read file
mov bx,filehandle ;
mov cx,10 ;10 bytes
push    ds
mov ds,[buffer] ;into allocated memory
mov     dx,0   
int 21h ;
pop ds
jc readfail ;

mov ah,3eh ;
mov bx,filehandle ;
int 21h ;
jc closefail ;

mov ah,02h ;print on screen
mov cx,10 ;
push ds
mov ds,[buffer] ;
xor di,di
L10: mov dl,[di] ;
int 21h ;
inc di ;
loop L10 ;
pop ds
;jmp finish ;

mov ah,49h ;
mov es,[buffer]
int 21h ;
jnc finish ;

mov ah,09
lea dx,freefail_msg
int 21h

readfail:
openfail:
freefail:
allocfail:
finish:
MOV AH,10H ;Request keyboard
INT 16H ;  input

MOV AX,4C00H ;End of processing
INT 21H
MAIN ENDP
END MAIN




I did some changes (without testing). Why?

the value returned by int 21h, ah=48 is a *segment* address


lianergoist

Quote from: japheth on December 13, 2006, 03:38:21 PM
I did some changes (without testing). Why?

the value returned by int 21h, ah=48 is a *segment* address

Yes, I know it is a segement address, but I couldn't figure out really how to access that allocated area. What you do, pushing and popping ds, is of course the way to do it. Thanks a lot.


Thomas