提问人:Tim 提问时间:11/5/2023 最后编辑:Sep RolandTim 更新时间:11/6/2023 访问量:91
Linux 和 Windows x86 程序集调用约定
Linux and Windows x86 assembly calling conventions
问:
据我所知,在 Linux 和 Windows 之间有两种常见的调用约定:函数调用的参数要么加载到寄存器中,要么放在堆栈上。
例如,对于函数,据说 Linux 加载了带有所需参数的寄存器。对于在 Windows 上,我已经看到使用了这两种约定。在我的课堂上,他们让我们将参数放在堆栈上,但是在在线代码示例中,参数被放置在寄存器中。printf
printf
printf
Basile Starynkevitch 的这个回答让我认为 Windows 只将堆栈用于参数,而 Linux 使用寄存器。Jester 的这个答案显示了 Windows 使用寄存器作为参数。printf
我为我的类编写的代码的下一个小部分显示,在 Windows 上,我一直在使用堆栈进行参数:
section .data
msg: db "my message", 0ah, 0
section .text
_main:
push msg
call _printf
add esp, 4
- 那么 Windows 是否能够同时使用这两种调用约定呢?
- 你怎么知道应该使用哪个?
- 32 位和 64 位 x86 程序有什么不同吗?
我还看到人们可以在没有下划线的情况下在 Windows 程序集中使用。我知道这对于 Linux 汇编代码来说是正常的,但在 Windows 上,如果我不使用下划线,我会收到错误。Windows 上的其他人似乎没有这个问题。printf
在 Jester 回答的原始问题(上面的链接)中,提出问题的用户似乎没有使用任何特殊的 NASM 指令来允许这样做,除非它是他们正在使用的链接器命令中的内容。
C. K. Young 只解释了如果您使用某个 NASM 选项,如何在没有下划线的情况下使用。printf
- 那么,为什么某些 Windows 程序集程序在不使用 NASM 选项时可以使用不带下划线呢?
printf
我搜索了很多,但没有找到这些奇怪案例的任何解释。
答:
32 位 x86 CPU 没有那么多寄存器可供使用,因此最初为它们设计的大多数调用约定主要使用堆栈。
这显然不如使用寄存器快,因此一旦 64 位 x86 CPU 变得更加普遍,参数就会尽可能多地存储在寄存器中。
要生成一个完全可用的应用程序,您需要将代码链接到“libc”;Windows 提供了至少 2 个 SDK ,并且还有独立的实现,例如 MinGW-w64 使用的实现;它们中的每一个都将使用您应该匹配的特定调用约定导出其函数,并且在名称中使用前导“_”通常是防止冲突调用成功链接的方式。
评论