【发布时间】:2018-02-07 20:40:05
【问题描述】:
在 64 位 NASM 中,我使用 C 库中的 malloc() 分配一个 8000 字节的内存块,当我完成它时,我通过调用 free() 来释放它。
我的研究提出了很多关于如何在 64 位 NASM 中执行此操作的相互矛盾的信息,其中大部分信息是 32 位的,其中调用约定不同,或者是 C 或 C++,而不是 NASM .
我认为我的 malloc 部分是正确的,但我不确定 free 部分。我发布这个问题是因为我不想测试它并且分配了一个内存块但没有释放。
所以我的两个问题很简单:
(1) 我对 64 位 NASM 有这个权利吗?
(2) Windows 和 Linux 的语法一样吗?
我只展示了我的程序的 malloc 和 free 部分:
extern malloc
extern free
push rdi
; Allocate the memory buffer
mov rdi,8000
call malloc
mov [array_pointer],rax ;array_pointer is initialized in .data
; Code that uses the buffer goes here.
; Free the memory buffer
push rdi
call free
add rsp,8
pop rdi
ret
【问题讨论】:
-
malloc返回 RAX 中的指针。您需要将 RAX 移动到 RDI(或将存储在array_pointer的地址移动到 RDI)以释放它(作为第一个参数free是通过 RDI 传递的,就像每个符合 64 位 System V ABI 的函数一样)。您也不需要call free周围的push rdi和add rsp, 8。这样做会弄乱堆栈对齐。 -
C 库是标准化的。您可以在 cppreference 站点找到所有函数及其参数。记忆功能可以在这里找到:en.cppreference.com/w/c/memory。无论是从 C 还是程序集调用
free都采用单个参数(指针)并且没有返回值。 .malloc采用单个参数(以字节为单位的大小)并返回一个指针(在 RAX 中)。cpp 参考中 C 库的索引在这里:@ 987654322@ -
通常我这样做的方式(没有堆栈帧并且不担心展开)是从 RSP 中减去 40 字节 +(本地所需的字节数(四舍五入到最接近的 16))。 . 在函数的开头。这意味着在一条指令中,我重新对齐 16 字节边界,分配所有本地空间,并一次性分配暂存空间。优点是我不需要担心函数中任何一点的对齐(和暂存空间),因为我已经确保所有分配和堆栈在开始时对齐。然后,我的本地变量将从 RSP+32 开始。
-
不正确。
malloc返回一个 16 字节对齐的地址,因此如果您使用需要对该指针进行对齐访问的指令(如 SSE),则它不会失败。但是,在调用malloc和free(以及使用 Windows 64 位调用约定的任何其他符合的函数)之前,您仍然需要确保堆栈是 16 字节对齐的,因为这些函数可能使用需要适当的 CPU 指令堆栈对齐以正确运行。如果堆栈未对齐时函数没有失败,请不要假设将来会出现这种情况。 -
我经常看到人们说“它可以在没有正确对齐的情况下工作,所以它已经足够好了”,然后当他们的代码意外开始崩溃并想知道为什么我们不得不回去时,他们会去寻求帮助说“对齐很重要,这样记录是有原因的”
标签: assembly malloc nasm x86-64 free