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.
- ↑ BUFFER
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.
-
enlarged
twice
┌ ╔════════╗ <─┐
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ free ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║ │
│ ║ ║<┐ │
enlarged │ ║░░░░░░░░║ │ │
once │ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │
┌ ╔════════╗ <─┐ ┌ ╔════════╗ <─┐ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║ ║ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║ ║<┐ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ free ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
created │ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║<┐ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
┌ ╔════════╗<──┐ ┌ ╔════════╗<──┐ │ ║░░░░░░░░║ │ │ ┌ ╔════════╗<──┐ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║ ║<┐ │ │ ║░░░░░░░░║ │ │ │ ║ ║<┐ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ free ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║ ║<┐ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
64KB│ ║░░░░░░░░║ │ │ 64KB│ ║░wasted░║ │ │ 128KB│ ║░░░░░░░░║ │ │ 64KB│ ║░wasted░║ │ │ 128KB│ ║░wasted░║ │ │ 256KB│ ║░░░░░░░░║ │ │
│ ║░payload║ │ │ │ ║░payload║ │ │ │ ║░payload║ │ │ │ ║░payload║ │ │ │ ║░payload║ │ │ │ ║░payload║ │ │
│ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │ │ ║░░░░░░░░║ │ │
│ ╟────────╢ │ │ │ ╟────────╢ │ │ │ ╟────────╢ │ │ │ ╟────────╢ │ │ │ ╟────────╢ │ │ │ ╟────────╢ │ │
│ ║.Ptr ╟─┘ │ │ ║.Ptr ╟─┘ │ │ ║.Ptr ╟─┘ │ │ ║.Ptr ╟─┘ │ │ ║.Ptr ╟─┘ │ │ ║.Ptr ╟─┘ │
│ ╟────────╢ │ │ ╟────────╢ │ │ ╟────────╢ │ │ ╟────────╢ │ │ ╟────────╢ │ │ ╟────────╢ │
│ ║.Top ╟───┘ │ ║.Top ╟───┘ │ ║.Top ╟───┘ │ ║.Top ╟───┘ │ ║.Top ╟───┘ │ ║.Top ╟───┘
│ ╟────────╢ │ ╟────────╢ │ ╟────────╢ │ ╟────────╢ │ ╟────────╢ │ ╟────────╢
│ ║.Prev=0 ║ │ ║.Prev=0 ║ │ ║.Prev ╟──────┐ │ ║.Prev=0 ║ │ ║.Prev ╟──────┐ │ ║.Prev ╟──────┐
│ ╟────────╢ │ ╟────────╢ │ ╟────────╢ │ │ ╟────────╢ │ ╟────────╢ │ │ ╟────────╢ │
│ ║.Last=0 ║ │ ║.Last ╟─────────┐ │ ║.Last=0 ║ │ │ ║.Last ╟─────────┐ │ ║.Last ║ │ │ ║.Last=0 ║ │
└ ╚════════╝<──┐ └ ╚════════╝<──┐ <┐ │ └ ╚════════╝<──┐ │ └ ╚════════╝<──┐ <┐ │ └ ╚════════╝ <────│──┐ └ ╚════════╝<──┐ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
aBuffer──────┘ aBuffer──────┘ │ └─────────────────────┘ │ aBuffer──────┘ │ └────────────────────────│──│──────────────────────┘ │
│ │ │ │ │ │
└───────────────────────────┘ └───────────────────────────┘ └─────────────────────────┘
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 Size=64K
- will allocate an empty (cleared) buffer from OS virtual memory.
- Input
- Size= is the initial size of the entire BUFFER plus payload data.
It will be rounded up to the fixed granularity 64 KB.
When underestimated, it will be automatically increased if necessary
but this wastes memory.
- Output
- CF=0, RAX=pointer to the BUFFER (buffer handle).
- Error
- CF=1, RAX=0 or error number when allocation error occured.
- Depends on
- macro MemAlloc defined in winabi.htm or linabi.htm.
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 aBuffer, aBuffer2, aBuffer3,,,
- will free the buffer, i. e. unallocate memory currently stored in the buffer
and its predecessors, if any.
- Input
- aBuffer is a pointer to the BUFFER structure
which was returned from BufferCreate
. It may be NULL.
- Output
- -
- Error
- -
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 aBuffer, DataPtr, DataSize
- will copy DataSize bytes of the data specified with DataPtr on the buffer.
- Input
- aBuffer is a pointer to a BUFFER structure
which was returned from BufferCreate.
DataPtr is a pointer to data to be stored on the buffer.
DataSize is the requested data size in bytes.
- Output
- CF=0, data were stored to the buffer.
- Error
- CF=1 on allocation error or not created buffer.
- Depends on
- BufferCreate
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 aBuffer
- will return pointer and size of all data currently stored in the buffer.
- Input
- aBuffer is a pointer to the BUFFER structure
which was returned from BufferCreate
. Macro returns RCX=RSI=0,CF=1 when aBuffer is NULL.
- Output
- CF=0
RSI=Pointer to the stored data (aBuffer+SIZE#BUFFER).
RCX=Size of the stored data (aBuffer.Ptr - (aBuffer+SIZE#BUFFER))
ZF=1 when RCX=0 (buffer exists and it is empty), otherwise ZF=0.
- Error
- CF=1,RCX=RSI=0 (uncreated buffer)
- Example
- BufferRetrieve RBX ; RBX is pointer to a buffer, or 0.
JNA .NoData: ; Jump when the buffer is empty (RCX=0,ZF=1) or hasn't been created (CF=1).
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 aBuffer
- will reset the buffer contents but does not free the allocated space.
- Input
- aBuffer is a pointer to the BUFFER structure
which was returned from BufferCreate
. Macro returns CF=1 when aBuffer is NULL.
- Output
- CF=0
- Error
- CF=1 (uncreated buffer)
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.
▲Back to the top▲