【问题标题】:Fastcall in 64 bit64位快速调用
【发布时间】:2023-03-07 09:59:01
【问题描述】:

我一直在阅读 32 位调用约定的差异。 fastcallstdcall 的考验就是这样。

根据我的阅读,这两种约定存在很大的混淆,64 位被标准化以避免这种混淆。

我不得不问,为什么选择fastcall

另外,由于 fastcallstdcall 是 win32 术语,那么 UNIX 术语中表示使用或不使用寄存器传递参数的函数调用是什么?

【问题讨论】:

  • 这不完全是 fastcall,它是“我们还有 8 个寄存器,让我们使用 'em”调用约定。
  • @hansPassant 使用寄存器进行参数传递确实没有任何节省,因为您通常必须事先将寄存器备份到堆栈上。 Fastcall 风格的调用仅在非常特定的情况下更快。
  • 您认为它们必须“备份”。一般来说,这不是一个正确的假设。代码生成器可以将它们视为临时文件或从内存中重新加载它们。 “让我们使用他们”方案不是“让我们全部使用”。
  • @hansPassant 点。我想我看到更多的问题是“被调用者”无论如何都需要使用寄存器并且必须在堆栈上备份 args,除非它是一个非常简单的函数。
  • 没有“64 位快速调用”之类的东西。 fastcall 纯粹是旧 32 位 x86 的产物。

标签: unix 64-bit x86-64 stdcall fastcall


【解决方案1】:

x86 Calling Conventions - Wikipedia, the free encyclopedia 提供了一个列表。

x86-32 上的通用调用约定是cdecl。 GCC提供了一个函数属性__attribute__((regparm(n)))来表示n参数是通过寄存器传递的,但这与fastcall不同。无论哪种方式,参数都在 callee-clobberable 寄存器中传递,因此对于相对于 cdecl(对于 regparm)和 @ 的函数调用而言,没有额外的成本(并且节省了为参数添加堆栈空间然后清理它的工作) 987654330@(用于fastcall)。

为了帮助您混淆,Windows 和 Linux 上的 x86-64 调用约定与 x86-32 上的调用约定以及彼此不同。 fastcall 也不是,尽管两者都使用大量寄存器来传递参数。

【讨论】:

  • 我对 BSD 更不满,因为他们一直都有基于堆栈的调用,这既简单又节省 CPU 时间,因为您不需要事先备份寄存器。根据我对您所说的理解,64 位似乎不需要寄存器传递?
  • @Hawken: regparmfastcall 使用被调用者破坏的寄存器,因此即使在 cdeclstdcall 下也需要调用者保存它们——浪费了多少 CPU 时间?目前,C 编译器没有使用非默认的 x86-64 调用约定。您可以查看System V Application Binary Interface \ AMD64 Architecture Processor SupplementMSDN | Overview of x64 Calling Conventions 了解当前正在使用的内容。
  • 甚至 FreeBSD 开发手册也指出寄存器传递速度较慢。我倾向于相信它们,因为 FreeBSD 开发人员可能会同时使用寄存器/堆栈传递程序进行测试,因为它们经常移植 Linux 代码。此外,假设您无论如何都需要将传递的值写入堆栈,因为您将在指令中使用%e_x 寄存器。除非你的函数只是调用另一个函数。
猜你喜欢
  • 2011-01-22
  • 1970-01-01
  • 2012-07-07
  • 1970-01-01
  • 2016-04-11
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
  • 2015-05-01
相关资源
最近更新 更多