This file contains OS-independent macroinstructions for dynamic memory management in 64bit programs written in Euro Assembler.
It requires that the program which includes this file "memory64.htm" also included either "winabi.htm" or "linabi.htm".
All macros in this library return carry flag set if some error occurs, which usually signalizes lack of system memory or bad parameter. Returned values are not valid when CF=1.
memory64 HEAD ; Library interface.
Object BUFFER is an unformated storage for objects (strings) of arbitrary size.
Items with fixed or variable size can be stored to the buffer one after another and the entire buffer content is always available as a continuous block.
The initial Size specified at the BUFFER creation should be large enough to accomodate all expected data. Whenever the total buffer size tries to exceed the allocated size specified at buffer creation, data area is reallocated with doubled size, the old buffer contents is copied to the new position and the original buffer space is abandoned.
BUFFER STRUC
.Last D QWORD ; Ptr to the last, active block. 0 if the current block is active. Other blocks are unused.
.Prev D QWORD ; Ptr to the previous memory block, or 0 if none. Used in BufferDestroy.
.Top: D QWORD ; Ptr to the top of this block (end of the allocated buffer space).
.Ptr: D QWORD ; Ptr to the next free space in the buffer.
ENDSTRUC BUFFER
BufferCreate %MACRO Size=64K
MOV RAX,%Size
CALL BufferCreate@RT
BufferCreate@RT:PROC1
PUSH RBX,RCX
MOV RBX,RAX
ADD RBX,64K-1
AND RBX,-64K
MemAlloc RBX ; Macro defined in winabi.htm or linabi.htm.
JC .90:
LEA RCX,[RAX+RBX]
MOV [RAX+BUFFER.Top],RCX
LEA RCX,[RAX+SIZE#BUFFER]
MOV [RAX+BUFFER.Ptr],RCX
.90: POP RCX,RBX
RET
ENDP1 BufferCreate@RT
%ENDMACRO BufferCreate
BufferDestroy %MACRO aBuffer, aBuffer2,,,
PUSH RCX
%WHILE "%1" !=== ""
MOV RCX,%1
JRCXZ BufferDestroy%.:
CALL BufferDestroy@RT
BufferDestroy%.:
%SHIFT 1
%ENDWHILE
POP RCX
BufferDestroy@RT: PROC1 ; RCX=^BUFFER.
PUSH RAX,RCX
PUSHQ [RCX+BUFFER.Prev]
MemFree RCX ; Macro defined in winabi.htm or linabi.htm.
POP RCX
JRCXZ .90: ; Skip when there was no previous buffer.
CALL BufferDestroy@RT: ; Otherwise destroy the previous buffers recursively.
.90: POP RCX,RAX
RET
ENDP1 BufferDestroy@RT:
%ENDMACRO BufferDestroy
BufferStore %MACRO aBuffer, DataPtr, DataSize
PUSHQ %DataSize, %DataPtr, %aBuffer
CALL BufferStore@RT::
BufferStore@RT:PROC1
PUSH RAX,RBX,RCX,RSI,RDI
MOV RBX,[RSP+6*8] ; aBuffer
TEST RBX
STC
JZ .90:
MOV RCX,[RBX+BUFFER.Last]
JRCXZ .20:
MOV RBX,RCX
.20: MOV RSI,[RSP+7*8] ; DataPtr
MOV RCX,[RSP+8*8] ; DataSize
MOV RAX,[RBX+BUFFER.Top]
MOV RDI,[RBX+BUFFER.Ptr]
SUB RAX,RDI ; Available memory remaining in the buffer.
CMP RCX,RAX
JBE .70: ; Jump when DataSize is lower.
PUSH RDX,RDI ; Old buffer is not large enough.
MOV RAX,[RBX+BUFFER.Top]
PUSH RAX
SUB RAX,RBX
ADD RAX,RAX ; Double the buffer size
ADD RAX,RCX ; and add the DataSize for a good measure.
CALL BufferCreate@RT: ; Create the new buffer with size=RAX.
POP RCX ; RBX is the old buffer, RCX its .Top, RAX is the new buffer.
JC .60: ; CF when allocation error ocurred.
MOV RSI,RBX ; RSI=Old buffer.
MOV RDI,RAX ; RDI=New buffer.
SUB RCX,RBX ; RCX=size of the old buffer.
MOV RDX,[RAX+BUFFER.Top] ; Temporarily backup the new buffer's .Top.
SHR RCX,3 ; Size in QWORDs.
REP MOVSQ ; Copy the entire old buffer including its contents.
MOV RCX,[RBX+BUFFER.Ptr] ; Convert old buffer's .Ptr to the new one.
SUB RCX,RBX
ADD RCX,RAX
MOV [RAX+BUFFER.Top],RDX ; Restore new buffer's .Top.
MOV [RAX+BUFFER.Ptr],RCX ; Update new buffer's .Ptr.
MOV [RAX+BUFFER.Prev],RBX
MOV [RAX+BUFFER.Last],0
MOV [RBX+BUFFER.Last],RAX
MOV RCX,[RBX+BUFFER.Prev]
.40: JRCXZ .50:
MOV [RCX+BUFFER.Last],RAX
MOV RCX,[RCX+BUFFER.Prev]
JMP .40:
.50: MOV RBX,RAX
CLC
.60: POP RDI,RDX
JC .90:
JMP .20:
.70: REP MOVSB
MOV [RBX+BUFFER.Ptr],RDI
CLC
.90: POP RDI,RSI,RCX,RBX,RAX
RET 3*8
ENDP1 BufferStore@RT:
%ENDMACRO BufferStore
BufferRetrieve %MACRO aBuffer
PUSHQ %aBuffer
CALL BufferRetrieve@RT:
BufferRetrieve@RT: PROC1
MOV RCX,[RSP+8]
MOV RSI,RCX
STC
JRCXZ .90:
MOV RCX,[RSI+BUFFER.Last]
JRCXZ .50:
MOV RSI,RCX
.50:MOV RCX,[RSI+BUFFER.Ptr]
LEA RSI,[RSI+SIZE# BUFFER]
SUB RCX,RSI
.90:RET 8
ENDP1 BufferRetrieve@RT:
%ENDMACRO BufferRetrieve
BufferClear %MACRO aBuffer
PUSH RAX,RCX
MOV RCX,%aBuffer
STC
JRCXZ BufferClearE%.:
MOV RAX,RCX
MOV RCX,[RAX+BUFFER.Last]
JRCXZ BufferClearD%.:
MOV RAX,RCX
BufferClearD%.:
LEA RCX,[RAX+SIZE# BUFFER]
MOV [RAX+BUFFER.Ptr],RCX
CLC
BufferClearE%.:
POP RCX,RAX
%ENDMACRO BufferClear
ENDHEAD memory64 ; End of the library interface.