memory-management - 动态堆分配困惑

标签 memory-management x86 heap masm irvine32

以下是Assembly Kip Irvine书中提供的代码。
我想知道这段代码在做什么。我了解
getProcessHeap返回该程序现有的32位整数句柄
EAX中的堆区域。如果要对函数进行排序,它将返回
EAX中堆的句柄。如果失败,则返回EAX中的值
一片空白

HeapAlloc从堆中分配一块内存。如果成功
EAX中的返回值包含内存块的地址。如果它
失败,EAX中返回的值为NULL。

在CALLOC中如何使用字符分配?

IALLOC中如何使用整数分配?

Hoe是否在LALLOC中使用了长整数分配?

在MALLOC中,如何从堆中分配字节大小?谢谢

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

最佳答案

尽管您对这些函数的描述本质上是正确的,但值得指出的是 GetProcessHeap HeapAlloc HeapFree 函数实际上是Win32 API函数,这意味着它们作为操作系统的一部分提供给应用程序调用。 Irvine的库刚刚提供了这些函数的原型(prototype),以使其易于调用。这样,可以通过阅读Microsoft的MSDN文档(上面的链接)直接从马口中获得这些功能的语义。

如文档所述,这是应用程序的一种常见模式,该应用程序需要分配适度大小的内存才能从进程的默认堆中获取该内存。这节省了创建和管理单独的专用堆(仅进行分配)的开销。 HeapAllocHeapFree(以及类似的名称)功能是您在现代Windows编程中应使用的功能,而不是您有时仍会在本世纪未更新的Windows编程 Material 中看到或使用的obsolete GlobalAlloc or LocalAlloc functions

现在,在您拥有的代码中,由于所有内容最终都可以返回到MALLOC,因此让我们从此处开始。它建立一个堆栈框架,调用GetProcessHeap,调用HeapAlloc,然后拆除堆栈框架。您应该立即看到一个错误。还记得您在GetProcessHeapHeapAlloc函数的描述中如何小心地描述了如果失败的话会发生什么?好吧,你是对的。这些功能可能会失败,因此正确编写的代码应检查错误并进行处理。此代码没有。

在MALLOC中,如何从堆中分配字节大小?
MALLOC的实现非常简单:它真正要做的就是获取进程堆的句柄,然后使用HeapAlloc从该堆中分配内存。因此,如果您想知道它是如何工作的,请返回the documentation for HeapAlloc 。由此可见,第一个参数是堆的句柄(从GetProcessHeap中的eax返回),第二个参数是控制分配的标志的按位组合(在这种情况下为8,或HEAP_ZERO_MEMORY),第三个参数参数是要分配的字节数(在这种情况下为[ebp + 8])。
[ebp + 8]读取传递到堆栈上MALLOC函数的第一个(可能是唯一的)参数。 ([ebp + 4]是指向调用函数的指针(其中MALLOC将为ret),而[ebp + 0]ebp的原始值,保存在进入MALLOC函数时保存。)

在我看来,这是MALLOC函数的另一个(次要)错误:没有充分记录!我们应该如何知道它需要一个参数,而不是参数的大小/类型和含义,而不深入研究其实现?函数的基本用途和接口(interface)应在代码中使用注释进行记录。

因此,问题的答案是,MALLOC分配的字节数与您要分配的字节数相同。

CALLOC如何使用字符分配?

这是包裹在MALLOC函数周围的简单宏。其目的基本上是根据要为其分配空间的字符数来确定要分配多少字节,然后将该值作为参数传递给MALLOC
CALLOC宏采用单个参数size,这是您要为其分配空间的字符数。 (顺便说一句,我认为size是该参数名称的不好选择,因为它不是很具描述性。)

然后,将调用者指定的size乘以字符所需的实际字节数,该字符数在汇编时由表达式sizeof BYTE确定。这将给出实际需要分配的字节数。 (现在,由于sizeof BYTE仅为1,这是非常愚蠢且效率低下的代码!我猜它被写为“可移植的”,但是请继续使用,它是汇编语言!)

最后,它将结果(要分配的字节数)压入堆栈,并调用MALLOC进行分配。

现在您了解了CALLOC的工作原理,您应该了解所有这些*ALLOC宏的工作原理,因为它们都是相同的。 IALLOC用短整数(sizeof WORD)的大小乘以其参数,以得出需要分配的实际字节数,而LALLOC用长整数(sizeof DWORD)的乘以其参数。

(请注意,尽管这些其他宏的乘法是必需的,但它们的效率也不高。sizeof WORD == 2,因此您可以左移1。或者,更好的是,将值加到自身上。sizeof DWORD == 4,因此左移2。加法和移位比乘法执行快得多。)

关于memory-management - 动态堆分配困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43647428/

相关文章:

delphi - 如果我不在完全 Debug模式下使用 FastMM4,它是否比 Delphi XE2 中的内存管理器快?

arrays - 如何操作*大量*数据

c - 反向字符串 realloc() : invalid next size

assembly - x86 sbb 与第一个和第二个操作数具有相同的寄存器

c - 非法内存读取或跳转后恢复IP寄存器

javascript - 优先队列中的比较器 : Javascript

data-structures - 堆是抽象数据类型吗?如果是这样,那么优先队列呢?

c - 在 C 中使用 malloc() 初始化大型数组时出现段错误

Python : Functional code speed is faster than pure code speed. 为什么?

assembly - 汇编语言将变量存储在特定地址