Dynamically Offset Heap Clusters
Below is the code from the Kip Irvine compilation. I want to know what this code does. I understand that getProcessHeap returns a 32-bit integer handle to an existing program heap area in EAX. If the function should have completed, it will return a heap descriptor in EAX. If this fails, return value in EAX NULL
HeapAlloc allocates a block of memory from the heap. If successful, the return value in EAX contains the address of the memory block. If it fails, the return value in EAX is NULL.
How is the character distribution used in CALLOC?
How is integer allocation used in IALLOC?
Hoe is this long integer allocation used in LALLOC?
In MALLOC, how is the size in bytes allocated from the heap? Thanks to
INCLUDE Irvine32.inc
HANDLE TEXTEQU <WORD>
GetProcessHeap PROTO
HeapAlloc PROTO,
hHeap : HANDLE,
dwflags: DWORD,
dwbytes: DWORD
HeapFree PROTO,
hHeap : HANDLE,
dwflags: DWORD,
lpmem : DWORD
.data
hHeap HANDLE ?
.code
CALLOC MACRO size
mov eax, sizeof BYTE
imul eax, size
push eax
call MALLOC
ENDM
IALLOC MACRO size
mov eax, sizeof WORD
imul eax, size
push eax
call MALLOC
ENDM
LALLOC MACRO size
mov eax, sizeof DWORD
imul eax, size
push eax
call MALLOC
ENDM
MALLOC PROC
push ebp
mov ebp, esp
invoke GetProcessHeap
invoke HeapAlloc, eax, 8, [ebp + 8]
pop ebp
ret 4
MALLOC ENDP
MEMFREE PROC
push ebp
mov ebp, esp
invoke GetProcessHeap
invoke HeapFree, eax, 0, [ebp + 8]
pop ebp
ret 4
MEMFREE ENDP
source to share
While your description of these functions is mostly correct, it is worth noting that GetProcessHeap
, HeapAlloc
and HeapFree
functions are actually Win32 API functions, which means they are provided as part of the operating system for application calls. The Irvine library has just provided prototypes for these functions to make them easier to call. So the semantics of these functions can be obtained directly from the horse's mouth by reading the Microsoft MSDN documentation (links above).
As the documentation explains, this is a common pattern for an application that needs to allocate a moderate amount of memory in order to simply get that memory from the process's default heap. This eliminates the need to create and the overhead of managing a separate personal heap, just for allocation. The functions HeapAlloc
and HeapFree
(and similarly named) are those that you should be using in modern Windows programming, not deprecated GlobalAlloc
or LocalAlloc
functions that are sometimes still seen used or referenced in Windows programming material that have not been updated in this century.
Now, in the code you have, since everything eventually comes back to MALLOC
, start there. It sets up a stack frame, calls GetProcessHeap
, calls HeapAlloc
, and then pops the stack frame. You should see the error immediately. Remember in describing features GetProcessHeap
and HeapAlloc
you were careful to describe what happens if they fail? Well, you were right; these functions can fail, and properly written code must check for errors and handle them. This code doesn't work.
In MALLOC, how is the size in bytes allocated from the heap?
The implementation is MALLOC
pretty straightforward: all it really does is get a handle to the process heap and then use it HeapAlloc
to allocate memory from that heap. So if you want to know how it works, go back to the documentation forHeapAlloc
. From this we can see that the first parameter is the heap descriptor (returned from GetProcessHeap
to eax
), the second parameter is a bitwise combination of flags that control the allocation (in this case 8 or HEAP_ZERO_MEMORY
), and the third parameter is the number of bytes to allocate (in this case [ebp + 8]
) ...
[ebp + 8]
reads the first (and presumably only) parameter that was passed to the function MALLOC
on the stack. ( [ebp + 4]
is a pointer to the calling function (where MALLOC
would be ret
), and [ebp + 0]
is the original value ebp
stored when entering the function MALLOC
.)
In my opinion this is another (minor) bug with the function MALLOC
: it is not well documented! How are we supposed to know that it takes a parameter, and even more so the size / type and value of this parameter, without delving into its implementation? The main function and function interface should be documented right in the code using a comment.
So the answer to your question is, MALLOC
allocates as many bytes as you ask it to allocate.
How is the character distribution used in CALLOC?
This is a simple macro wrapped around a function MALLOC
. Its purpose is to determine how many bytes to allocate based on the number of characters you want to allocate for space, and then pass that value as a parameter MALLOC
.
The macro CALLOC
takes a single parameter size
, which is the number of characters for which you want to allocate space. (By the way, I think it size
is a bad choice of name for this parameter, since it is not very descriptive.)
It then multiplies the specified by the tag size
by the specified number of bytes required by the character, which is determined at build time by the expression sizeof BYTE
. This will give the number of bytes that really should be allocated. (Now, since it sizeof BYTE
is just 1, this is pretty stupid and inefficient code! I think it was written as "portable", but will come to assembly language!)
Finally, it pushes the result (the number of bytes allocated) onto the stack and calls MALLOC
to perform the allocation.
And now that you understand how it works CALLOC
, you should understand how all these macros work *ALLOC
, since they are all the same. IALLOC
multiplies its parameter by the size of the short integer ( sizeof WORD
) to get the actual number of bytes to allocate, and LALLOC
multiplies its parameter by the size of the long integer ( sizeof DWORD
).
(Note that while the multiplications in these other macros are necessary, they are also ineffective. sizeof WORD
== 2, so you can just shift left by 1. Or, better yet, add a value for yourself. sizeof DWORD
== 4, so left shift by 2. Additions and shifts are much faster than multiplications.)
source to share