据我所知,Linux 和 Windows 之间有两种常见的调用约定:函数调用的参数要么加载到寄存器中,要么放置在堆栈上。
例如,使用
printf
函数,据说 Linux 会使用 printf
所需的参数加载寄存器。对于 Windows 上的 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 程序集中使用
printf
,而无需使用下划线。我知道这对于 Linux 汇编代码来说是正常的,但在 Windows 上,如果我不使用下划线,我会收到错误。 Windows上的其他人似乎没有这个问题。
在 Jester 回答的原始问题(上面的链接)中,提出问题的用户似乎没有使用任何允许这样做的特殊 NASM 指令,除非他们正在使用的链接器命令中包含某些内容。
C. K. Young 仅解释 如果您使用某个 NASM 选项,如何使用不带下划线的
printf
。
printf
呢?我已经搜索了很多,但没有找到这些奇怪案例的任何解释。
32 位 x86 CPU 没有那么多寄存器可供使用,因此大多数最初为其设计的调用约定主要使用堆栈。
这显然不如使用寄存器快,因此一旦 64 位 x86 CPU 变得更加普遍,参数就会尽可能地存储在寄存器中。
要生成一个完全工作的应用程序,您需要将代码链接到“libc”; Windows 通过其 SDK 提供了至少其中 2 个,并且还有独立的实现,例如 MinGW-w64 使用的实现;每个函数都将使用您应该匹配的特定调用约定导出其函数,并且在名称中使用前导“_”通常可以防止冲突调用成功链接。