【问题标题】:Compiler explorer and GCC have different outputs编译器资源管理器和 GCC 有不同的输出
【发布时间】:2020-05-18 10:41:06
【问题描述】:

我有一些 C 代码,当提供给 Compiler Explorer 时,它会输出:

        mov     BYTE PTR [rbp-4], al
        mov     eax, ecx
        mov     BYTE PTR [rbp-8], al
        mov     eax, edx
        mov     BYTE PTR [rbp-12], al

但是,如果我使用 GCC 或 G++,那么它会给我这个:

        mov     BYTE PTR 16[rbp], al
        mov     eax, edx
        mov     BYTE PTR 24[rbp], al
        mov     eax, ecx
        mov     BYTE PTR 32[rbp], al

我不知道为什么 BYTE PTR 不同。他们的地址完全错误,我不明白为什么他们在 [rdp] 部分之前。

如果您知道如何使用 gcc 或 g++ 重现第一个输出,请帮助!

【问题讨论】:

  • 你的 gcc 版本是多少?请注意,偏移量可能仍然正确,具体取决于 rbp 之前的设置方式。还有可用的红色区域。
  • gcc.exe (GCC) 8.2.0
  • 那是窗户。代码会有所不同,特别是因为 windows 有红色区域。
  • 我正在尝试用它来写一个qemu内核所以...
  • 然后由您决定要遵循哪个 ABI。此外,您可能希望启用优化。

标签: c++ c gcc assembly g++


【解决方案1】:

gcc.exe (GCC) 8.2.0

看起来像 Windows x64 调用约定的 GCC 正在使用其调用者保留的影子空间(返回地址上方 32 个字节)。 Godbolt 的 GCC 安装目标 GNU/Linux,即 x86-64 System V ABI。

您可以在 Godbolt 上通过使用 __attribute__((ms_abi)) 标记您的函数来获得相同的代码。当然,这意味着您的调用者必须在原型中看到该属性,以便知道保留该空间,以及将函数参数传入哪些寄存器。

Windows x64 调用约定大多比 x86-64 System V 差;例如,更少的参数传递寄存器。它的唯一优点之一是更容易实现可变参数函数(因为阴影空间),并且具有一些保留调用的 XMM regs。 (可能太多,但 x86-64 SysV 为零。)因此,您更有可能希望在 Windows 上使用交叉编译器(针对 GNU/Linux),或者在所有函数上使用 __attribute__((sysv_abi))。 (https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html)

调用约定的 XMM 部分通常与内核代码无关;大多数内核通过不让编译器使用 SIMD/FP 指令来避免在内核进入/退出时保存/恢复 SIMD/FPU 状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多