我有几个组装项目要实现,我对何时在堆栈上添加空间以及应该添加多少感到困惑。
我在 unix 系统 (macos) 英特尔x86_64上使用 NASM 版本 2.13.03。
我一直在阅读很多文档并做了很多研究,但没有一个以足够详细的方式解释我问题的答案。 我理解红色区域,并且叶函数不需要使用增加的堆栈。
我知道应该在函数调用之前使用通过使用 sub rsp 来增加堆栈,并且在函数调用之后应该使用添加 rsp。
我知道在 32 位架构上,您使用推送和弹出来增加堆栈,但在这个 64 位架构上,需要使用 sub rsp 并添加 rsp 以及 mov 指令来添加堆栈上的寄存器。
如果有人对使用此架构的堆栈有任何提示或解释,并解释何时增加堆栈以及应该提供多少,非常感谢!
一些 x86-64 堆栈原则:
根据两种主要的调用约定,堆栈需要在函数调用之前对齐16 字节,包括 MacOS 上使用的 x86-64 System V ABI。如果不是,则在调用外部函数时将面临分段错误的风险。 (例如,因为它们被允许假定对齐并将movaps
用于堆栈内存之间的 16 字节副本。
有趣的事实 - 在MacOS上,当堆栈未对齐16字节时,系统调用确实可以正常工作。
对于push rax
rax 值被推到堆栈顶部。
对于sub rsp,8
,堆栈的顶部保持不变(因此内存中存在的任何内容都将保留在那里)。 对于两条指令,对 rsp 值的更改完全相同。
例如,您可以执行以下任一操作:
sub rsp,16
或
push rax
push rax
堆栈指针rsp
指向完全相同的位置。
对于仅移动堆栈指针 8 个,虚拟推送或弹出可以与add/sub
一样高效或更高效。 除此之外,通常不会。