[NASM我应该在调用func之后弹出函数参数吗?

问题描述 投票:1回答:2

假设我具有这样的nasm功能:

inc:
    mov rax,[rsp + 8]
    add [rax],BYTE 1
    ret

我正在这样调用此函数:

push some_var
call inc

我想通过堆栈将参数传递给函数,所以我按下了some_var,然后调用了我的函数。在功能上,我的项目在堆栈上排在第二位,因此我将其视为:mov rax,[rsp+8]

我的问题是:调用函数后,我应该以某种方式从堆栈中弹出参数吗?如果是这样,我可以以某种方式将其从堆栈中删除,我的意思是弹出它,但不进行注册? (因为我不再需要此arg了)

更新:我发现我可以简单地add rsp,8,以及如何从堆栈中删除项目。但这是好习惯吗?要在调用函数后从堆栈中删除arg?

assembly x86-64 nasm callstack calling-convention
2个回答
0
投票

最佳实践是在寄存器中传递args,例如编译器使用的标准x86-64调用约定。例如x86-64系统V在寄存器中传递了前6个整数/指针args,因此您的功能应为add byte [rdi], 1/ ret,并且不需要任何清理。呼叫者只需要mov edi, some_varlea rdi, [rel some_var]

如果您do需要传递一个堆栈arg,则将其弹出到一个像pop rcx这样的虚拟寄存器中实际上比add rsp, 8效率更高[[more,原因与为何编译器有时会使用一个虚拟变量类似push保留一个qword堆栈插槽/按16:重新对齐堆栈。Why does this function push RAX to the stack as the first operation?但是,如果您有多个堆栈arg供调用者清理,请使用add rsp, 8 * n其中n是堆栈插槽的数量。

也可以使被呼叫者使用ret 8来清洁堆栈。但这使您失去了让调用方离开分配的堆栈空间并在其中进行mov存储的机会,例如正在准备另一个call

0
投票
我在此答案中列出了一些从堆栈中删除内容的方法:Can I POP a value from the stack, but put it nowhere in NASM Assembly?,总结一下:

  • add rsp, x
  • lea rsp, [rsp + x]
  • mov rsp, rbp(也是leave的一部分)
  • lea rsp, [rbp - x]
  • 弹出未使用的寄存器

除此之外,是否

应该从调用者的堆栈中删除参数取决于您的调用约定是强制执行caller clean-up还是执行相反的被调用者清理。通过指定要从堆栈中删除的字节数作为retn指令的立即操作数来完成被调用方清除。例如:

... ; caller code push rax push rdi call function ... ; function code push rbp mov rbp, rsp mov rcx, qword [rbp + 16] ... mov rsp, rbp pop rbp retn 16
© www.soinside.com 2019 - 2024. All rights reserved.