ziy*_*uxe 4 assembly callstack x86-64 nasm calling-convention
假设我有一个像这样的 nasm 函数:
inc:
mov rax,[rsp + 8]
add [rax],BYTE 1
ret
Run Code Online (Sandbox Code Playgroud)
我这样调用这个函数:
push some_var
call inc
Run Code Online (Sandbox Code Playgroud)
我想通过堆栈将参数传递给函数,因此我压入some_var然后调用我的函数。在函数中,我的项目位于堆栈中的第二个,因此我将其视为:mov rax,[rsp+8]
我的问题是:调用函数后我应该以某种方式从堆栈中弹出我的参数吗?如果是这样,我可以以某种方式从堆栈中删除它,我的意思是弹出它,但不注册?(因为我不再需要这个论点了。)
更新:我发现我可以简单地add rsp,8从堆栈中删除项目。但这是好的做法吗?调用函数后从堆栈中删除参数?
最佳实践是在寄存器中传递参数,就像编译器使用的标准 x86-64 调用约定一样。例如,x86-64 System V 在寄存器中传递前 6 个整数/指针参数,因此您的函数将是
add byte [rdi], 1/ ret,并且不需要任何清理。
调用者只需要mov edi, some_varor lea rdi, [rel some_var]。
(用户空间函数调用的基础知识记录在 i386 和 x86-64 上 UNIX & Linux 系统调用的调用约定是什么中,即使标题提到了系统调用。完整详细信息请参见https://github.com/hjl-tools/ x86-psABI/wiki/X86-psABI。实际查看编译器对简单 C 函数执行的操作也很方便:请参阅如何从 GCC/clang 程序集输出中删除“噪音”?)
如果您确实需要传递堆栈参数,则将其弹出到虚拟寄存器中pop rcx实际上比更有效add rsp, 8,原因与编译器有时使用虚拟寄存器push保留一个 qword 堆栈槽/将堆栈重新对齐 16 的原因类似:为什么该函数是否将 RAX 压入堆栈作为第一个操作? 但是,如果有超过 1 个堆栈参数供调用者清理,请使用
add rsp, 8 * nwheren是堆栈槽数。
也可以让被调用者使用 来清理堆栈ret 8。但这就失去了让调用者保留分配的堆栈空间并mov在其中进行存储的机会,例如为另一个call.
| 归档时间: |
|
| 查看次数: |
1212 次 |
| 最近记录: |