用于最大调用的约定 x86系统之间的可移植性

问题描述

我正在研究一组独立的x86汇编例程,我希望这些例程可用于以下系统上的C程序:

  • 仅Linux 64位
  • Windows 32位和64位
  • (最终可以使用64位Mac操作系统,但尚不清楚,因为苹果似乎正在放弃使用x86替代ARM的方式)

我已经以其他身份使用LLVM,并且几乎可以肯定我会使用clang而不是gcc,尽管我可以设想有人想要使用gcc编译全部内容。汇编程序将是NASM。

我既开发了例程,又开发了C库以向用户公开它们,即,一切都在我的控制之下,我可以根据需要设计一切。

我希望某些用户实际上会使用C ++,但他们仍将链接到C库-即,不直接与汇编例程链接。

作为我的新手,我正在发现一个迷宫,这些迷宫遍布系统,编译器,供应商,调用变体和语言,其中包含各种调用约定。我不能说它有时并不能带来有趣的阅读效果,但是我也不能说它对初学者没有混淆。

在阅读完所有内容后,我的看法是,最终,我可以从cdecl开始,以便在初始版本中获得最大的可移植性,然后在需要时考虑使用特殊大小写以涵盖其他约定-取决于例行程序实际上可以使我在特定情况下通过使用其他约定来使事情更快。

但是,起初,我想让某些东西能够正常运行,然后进一步对其进行优化-是否说在 cdecl 上安装将在我列出的系统之间提供最大的可移植性?谢谢。

解决方法

x86-64 Linux和MacOS都使用x86-64 System V ABI。 Windows使用其自己的调用约定。这些x86-64平台均未将其称为“ cdecl”。

通常的方法是让您的库对目标平台使用标准的调用约定,这意味着每个平台都有不同的asm。解决此问题的一种方法是使用asm宏,以使函数的顶部适应不同的调用约定。或参数化寄存器名称,例如ARG1而不是对RDI进行硬编码,但是如果您的函数超过了微不足道的指针增量,或者您曾经将寄存器用于函数arg之外的其他东西,这将变得非常复杂。

在32位窗口中,您可以选择多种约定; fastcall / vectorcall是吸人最少的两个。在其他所有x86 32和64位平台上,都有一个标准的调用约定。如果您关注图书馆,人们使用起来会更容易。

Agner Fog的调用约定指南对处理手写asm的可移植性提供了一些更详细的建议。 https://www.agner.org/optimize/


理论上您可以在任何地方使用x86-64 System V,但是在Windows上,MSVC将无法发出对您代码的调用。 (与GNU C兼容的编译器,例如gcc,clang和ICC可以在Windows的原型中使用long first = arr[0]; long second = arr[1]; long third = arr[2]; long fourth = arr[3]; long fifth = arr[4]; long min = first + second + third + fourth; long Max = second + third + fourth + fifth; ,在Windows的原型中,它们的默认调用约定是MS所命名的x64 fastcall。)

我想您可以在任何地方使用x86-64快速调用,并在非MSVC编译器的原型中使用__attribute__((sysv_abi))但这可能会花费一些性能开销,尤其是如果您想使用所有XMM注册表。 (xmm6..15在x64快速通话中保留了通话)。但是要当心编译器错误;使用非默认调用约定的测试还不够好。

如果所有函数的总寄存器args少于或等于4,则在大多数方面来说调用约定还不错。否则,更多的寄存器参数通常会更有效。 Why does Windows64 use a different calling convention from all other OSes on x86-64?


32位和64位明显不同。没有一个标准的调用约定在32位和64位代码之间兼容,并且您的代码通常总是需要完全不同的。

唯一真正的相似之处是32位Windows快速调用和标准64位Windows调用约定(MS也将其称为快速调用)之间的区别,但是32位快速调用仅传递regs中的前2个args,并且被调用者为pop堆栈参数。 64位快速调用将regs中的前4个参数传递给reg,从相同的2开始,然后使用仅在64位模式下存在的r8和r9。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...