assembly - NASM 调用函数后我应该弹出函数参数吗?
问题描述
假设我有一个这样的 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
从堆栈中删除项目。但这是好的做法吗?调用函数后从堆栈中删除参数?
解决方案
最佳实践是在寄存器中传递参数,例如编译器使用的标准 x86-64 调用约定。例如 x86-64 System V 在寄存器中传递前 6 个整数/指针参数,因此您的函数将是
add byte [rdi], 1
/ ret
,并且不需要任何清理。
调用者只需要mov edi, some_var
or lea rdi, [rel some_var]
。
(用户空间函数调用的基础知识记录在What are the call conventions for UNIX & Linux system calls on i386 and x86-64即使标题提到了系统调用。完整的细节在https://github.com/hjl-tools/ x86-psABI/wiki/X86-psABI。实际查看编译器对简单 C 函数的作用也很方便:请参阅如何从 GCC/clang 程序集输出中删除“噪声”?)
如果您确实需要传递一个堆栈 arg,将其弹出到一个虚拟寄存器中实际上pop rcx
可能比此函数是否将 RAX 作为第一个操作推入堆栈? 但是,如果您有超过 1 个堆栈参数供调用者清理,则使用where是堆栈槽的数量。add rsp, 8
push
add rsp, 8 * n
n
也可以让被调用者使用ret 8
. 但这会让您失去让调用者离开分配的堆栈空间并对其进行mov
存储的机会,例如为另一个call
.
推荐阅读
- libgdx - 围绕内部和外部点旋转 Sprite Libgdx
- regex - 如果不包含特定单词,则匹配字符串
- java - 如何从 sql 报告服务服务器生成 ReportExecutionService
- security - 浏览器中的 GoogleDrive API V3:公开的客户端 ID 和 API 密钥。有什么安全问题吗?
- laravel - Laravel Eloquent 增量而不更新时间戳
- tcl - 使用 glob 将变量设置为文件名
- python - 多标签计算类权重 - 不可散列的类型
- javascript - Google api 密钥不起作用,出现错误“糟糕!出了点问题。”
- javascript - 如何遍历一个数字数组以查看哪些数字与另一个数字相关?
- css - 另一个div顶部的css绝对位置