【问题标题】:NASM should I pop function argument after calling a function?NASM 调用函数后我应该弹出函数参数吗?
【发布时间】:2020-07-04 22:21:49
【问题描述】:

假设我有一个像这样的 nasm 函数:

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

我这样调用这个函数:

push some_var
call inc

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

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

更新:我发现我可以简单地add rsp,8,这就是我可以从堆栈中删除项目的方法。但这是好的做法吗?调用函数后从堆栈中删除参数?

【问题讨论】:

  • 您可以将参数从堆栈中弹出或增加堆栈指针以将其删除。两者都很好并且被编译器使用。

标签: assembly x86-64 nasm callstack calling-convention


【解决方案1】:

最佳实践是在寄存器中传递参数,例如编译器使用的标准 x86-64 调用约定。例如x86-64 System V 在寄存器中传递前 6 个整数/指针参数,因此您的函数将是
add byte [rdi], 1 / ret,不需要任何清理。
调用者只需要mov edi, some_var 或lea rdi, [rel some_var]。

(What are the calling conventions for UNIX & Linux system calls on i386 and x86-64 中记录了用户空间函数调用的基础知识,尽管标题提到了系统调用。https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI 中的完整详细信息。实际查看编译器对简单 C 函数所做的工作也很方便:请参阅How to remove "noise" from GCC/clang assembly output? )

如果您确实需要传递一个堆栈参数,出于类似原因,将其弹出到像pop rcx 这样的虚拟寄存器实际上可能比add rsp, 8 更高效为什么编译器有时使用虚拟 push 来保留一个 qword 堆栈槽/将堆栈重新对齐 16:Why does this function push RAX to the stack as the first operation? 但是如果您有超过 1 个堆栈 arg 供调用者清理,请使用
@987654333 @ 其中n 是堆栈槽的数量。

也可以使用ret 8 让被调用者清理堆栈。但这会让您失去让调用者离开分配的堆栈空间并在其中执行 mov 存储的机会,例如为另一个call做准备。

【讨论】:

【解决方案2】:

我在这个答案中列出了一些从堆栈中删除东西的方法: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 或相反的被调用者清理。通过将要从堆栈中删除的字节数指定为an immediate operand 到retn 指令来完成被调用者清理。例如:

    ...
    ; caller code
    push rax
    push rdi
    call testfunction
    ...


    ; function code
testfunction:
    push rbp
    mov rbp, rsp
    mov rcx, qword [rbp + 16]
    ...
    mov rsp, rbp
    pop rbp
    retn 16

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2012-11-01
    • 1970-01-01
    • 2020-05-01
    • 2017-08-30
    • 1970-01-01
    • 2012-08-18
    相关资源
    最近更新 更多