Linux 和 Windows x86 程序集调用约定

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

据我所知,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 能够使用这两种调用约定吗?
  • 你怎么知道应该使用哪个?
  • 32位和64位x86程序有什么不同吗?

我还发现人们可以在 Windows 程序集中使用

printf
,而无需使用下划线。我知道这对于 Linux 汇编代码来说是正常的,但在 Windows 上,如果我不使用下划线,我会收到错误。 Windows上的其他人似乎没有这个问题。

在 Jester 回答的原始问题(上面的链接)中,提出问题的用户似乎没有使用任何允许这样做的特殊 NASM 指令,除非他们正在使用的链接器命令中包含某些内容。
C. K. Young 仅解释 如果您使用某个 NASM 选项,如何使用不带下划线的

printf

  • 那么为什么有些 Windows 汇编程序在不使用 NASM 选项时可以使用不带下划线的
    printf
    呢?

我已经搜索了很多,但没有找到这些奇怪案例的任何解释。

linux windows assembly x86 nasm
1个回答
0
投票

32 位 x86 CPU 没有那么多寄存器可供使用,因此大多数最初为其设计的调用约定主要使用堆栈。

这显然不如使用寄存器快,因此一旦 64 位 x86 CPU 变得更加普遍,参数就会尽可能地存储在寄存器中。

要生成一个完全工作的应用程序,您需要将代码链接到“libc”; Windows 通过其 SDK 提供了至少其中 2 个,并且还有独立的实现,例如 MinGW-w64 使用的实现;每个函数都将使用您应该匹配的特定调用约定导出其函数,并且在名称中使用前导“_”通常可以防止冲突调用成功链接。

© www.soinside.com 2019 - 2024. All rights reserved.