c++ - 警告 #13212 : Reference to ebx in function requiring stack alignment

标签 c++ assembly

我正在尝试使用 ICC 2018 编译以下代码:

__asm {
        mov ebx, xx              ;xx address to registers
}

其中 xx 是 int16 类型。这是我的函数中的第一条指令。

我使用上面的汇编代码收到以下警告:
警告 #13212:在需要堆栈对齐的函数中引用 ebx

令人惊讶的是,当我用 eax 或 esi 替换 ebx 时,我看到警告消失了。我不明白为什么我只看到 ebx 的问题,据我所知,ebx 和 eax 都具有相同的架构(32 位寄存器)。

另外,当我用 ICC 2013 编译相同的代码时,我没有看到警告。

谁能帮我解决这个警告?

谢谢!

最佳答案

如果需要额外对齐,所选平台上的编译器(ICC,因为它模仿 MSVC 的行为)使用 EBX 来保存原始堆栈指针值。因此,您无法安全地覆盖它。
程序的行为将变得不确定。编译器警告只是告诉你这一点。

为了帮助保存/恢复受汇编 block 影响的所有寄存器,建议使用具有所谓的 clobber 列表的扩展语法。您的示例使用 MSVC 样式 __asm{...}句法。在 MSVC 风格的语法中,编译器检测您接触的寄存器并为您保存/恢复它们。
ICC 还支持类似 GCC 的表示法,用于扩展 asm 和 clobber 列表:asm("...":::) .它还支持更简单的 GCC asm("...")没有clobber列表部分。看到这个 question了解更多详情(感谢 Peter Cordes 的链接和解释)。

我在学习使用 clobber 列表时发现有用的文档(我实际上一直在使用它,因为不可能记住它对人类不友好的语法):

  • https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5
  • https://software.intel.com/en-us/node/694235

  • 没有 clobber 列表的简单内联汇编 block 只能在以下情况下安全使用:
  • block 的指令不会修改 ABI 中定义的寄存器。因此 GPR、堆栈计数器、标志应该保持不变;如果函数中有浮点计算,FPU/vector 寄存器也不受限制。即使是内存写入也会导致错误,因为编译器依赖于驻留在内存中的已知值。相比之下,可以发出 INT3 , HLT , WRMSR etc 指令要么不接触寄存器,要么只影响编译器不使用的系统寄存器。但是,大多数此类指令是特权指令,不能在用户应用程序中使用。还可以读取所有可用的寄存器,前提是此类读取没有副作用。
  • 汇编程序 block 是函数体中唯一的语句。在这种情况下,它必须遵守所选平台的调用约定:如何传递函数的参数,应将其退出代码放置在哪里等。该 block 还需要处理编译器生成的序言和结尾代码块,这些代码块具有它们的自己对寄存器的假设。他们的代码不是严格稳定的,也不是可移植的,也不能保证在不同的优化级别下是相同的。使用 x86 上的 GCC,我无法禁用序言/尾声生成,因此仍然存在违反编译器假设的风险。
  • 您自己保存所有损坏的寄存器并在之后恢复它们。这相对容易,因为您可以看到自己的汇编代码,并且可以判断寄存器是否被它修改。但是,犯了一个错误,编译器不会在这里为您指出。尽管 ICC 2018 可以将 asm block 视为黑匣子,但实际上发出警告是非常好的。
  • 你从编译器“偷”了一个寄存器。 GCC 允许使用 register asm 做到这一点语句(不记得相同的技巧是否适用于其他编译器)。因此,您可以声明一个变量绑定(bind)到某个寄存器。请注意,这种技术会减少编译器在其寄存器分配阶段可用的寄存器数量,这会降低其生成的代码质量。请求过多的寄存器,编译器会束手无策,拒绝工作。类似地,不能要求从编译器中删除具有专用角色的寄存器,例如堆栈指针或程序计数器。

  • 也就是说,扩展 asm使用 clobber 列表的语法提供了一个不错的选择。它变成了 asm从黑盒到内联内部“函数”的部分,该函数声明了自己的输入、输出和资源,它覆盖了与外部函数共享的资源。

    关于c++ - 警告 #13212 : Reference to ebx in function requiring stack alignment,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49023844/

    相关文章:

    c++ - 用tm加减时间

    linux - 使用 kprobes 获取函数参数

    android - Android 的 ARM 汇编程序中对 'printf' 的 undefined reference

    c++ - 没有ALU的ARM需要多少运算量

    c++ - 使用C++20 Concept约束模板参数

    c++ - 使用 Arduino UNO R3 将 ESP8266-01 连接到 WiFi 网络

    c++ - 使用字符串的变量将字符串拆分为字符数组

    c++ - 疯狂的 Mac 动态库(可能仅限 Fortran)

    C 代码表示为汇编代码 - 如何解释?

    linux - 为什么 Linux 内核复制实现使用 Acflags?