【问题标题】:Is it possible to convince GCC to mimic the fastcall calling convention?是否可以说服 GCC 模仿 fastcall 调用约定?
【发布时间】:2008-10-03 02:51:57
【问题描述】:

所以我有一个程序集需要在 windows 上使用 fastcall 调用约定调用一个函数,但 gcc 不(afaict)支持它。 GCC 确实提供了 regparm 属性,但是它期望前 3 个参数在 eax、edx 和 ecx 中传递,而 fastcall 期望前两个参数在 ecx 和 edx 中传递。

我只是试图避免有效地复制一些代码路径,所以这并不是很关键,但如果可以避免那就太好了。

【问题讨论】:

  • 请注意,实际上没有所谓的“the” fastcall 调用约定。您所描述的内容与 C++ Builder 所指的 fastcall 相匹配。在这种情况下,Visual C++ 似乎是一个奇怪的选择,不管它的价值。

标签: gcc visual-c++


【解决方案1】:

GCC 确实支持fastcall,通过__attribute__((fastcall))。它似乎已在 GCC 3.4 中引入。

【讨论】:

  • 前两个参数是否从右到左传递并分别放在edxecx 中?
  • @jww GCC manual 说“fastcall 属性导致编译器在寄存器 ECX 中传递第一个参数(如果是整数类型)和第二个参数(如果是整数类型)在注册 EDX。” Microsoft's __fastcall 的第一个和第二个参数的 ECX、EDX 顺序相同,从左侧开始。我不知道你为什么要从右边开始看论点......
  • “我不知道你为什么要从右边开始看参数......” - 我相信这就是被调用者传递它们的方式 - 从右到左.考虑一下,如果有四个参数,两个在堆栈中传递,两个在寄存器中传递。在这种情况下,从左到右的“第一个”参数是在堆栈上传递的,而不是寄存器。
  • @jww 我看到的每个 C 调用约定都有一个从最左边的参数到寄存器的固定映射(在 cdecl 的情况下可能没有),而最右边的参数是溢出到堆栈。现在,大多数调用约定(Pascal 除外)的左侧参数在堆栈上高于右侧参数,这可以看作是首先将最右侧的参数推入堆栈。但我从未见过调用约定将最右边的参数放在寄存器中并将最左边的参数溢出到堆栈中。
【解决方案2】:

我知道我参加这个聚会有点晚了,但是如果你们中的任何人偶然发现了这一点,请记住,您可以定义一个宏来模仿它。例如:

#if defined(__GNUC__)
    #define MSFASTCALL __fastcall
    #define GCCFASTCALL 
#elif defined(_MSC_VER)
    #define MSFASTCALL
    #define GCCFASTCALL __attribute__((fastcall))
#endif

int MSFASTCALL magic() GCCFASTCALL;

显然,这看起来有点难看,因此您可以定义 2 个原型(我就是这样做的)以使其更易于阅读,但有些人更喜欢需要较少输入的路线。除了特殊情况,我一般不使用调用约定。我只是让编译器优化其余部分。

现在,有一些怪癖需要记住。例如,当您针对 64 位平台时,所有函数都使用 fastcall 约定以利用额外的寄存器并提高速度并降低间接成本。同样,不同平台的 fastcall 实现方式也不同,因为它不是标准化的。还有一些其他的,但这是我能想到的。

【讨论】:

    【解决方案3】:

    如果您从 asm 调用函数,那么您肯定可以完全控制调用函数的方式。是什么阻止您加载寄存器并发出CALL

    【讨论】:

    • 问题是调用者在汇编程序中,我正在调用的函数在 C 中——这是我正在调用的函数的编译器的代码生成 :-(
    • 啊啊...是的,我以为你关心的是调用者而不是被调用者。
    • 别担心,我认为这是混乱:D
    猜你喜欢
    • 2021-12-20
    • 2014-04-15
    • 1970-01-01
    • 2011-03-01
    • 2023-03-28
    • 2018-12-16
    • 2021-02-21
    • 2016-01-13
    • 2016-05-05
    相关资源
    最近更新 更多