警告#13212:引用需要堆栈对齐功能的EBX

warning #13212: Reference to ebx in function requiring stack alignment

本文关键字:对齐 功能 EBX 堆栈 #13212 引用 警告      更新时间:2023-10-16

我试图用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使用EBX保存原始堆栈指针值,如果需要附加对齐。因此,您不能安全地覆盖它。该程序的行为将变得不确定。编译器警告只是告诉您这一点。

为了帮助保存/还原受汇编块影响的所有寄存器,建议使用带有所谓的Clobber列表的扩展语法。您的示例使用MSVC风格的__asm{...}语法。在MSVC风格的语法中,编译器检测您触摸的寄存器并为您保存/还原它们。ICC还支持带有Clobber列表的扩展ASM的类似GCC的符号:asm("...":::)。它还支持更简单的GCC asm("..."),而无需Clobber列表部分。有关更多详细信息,请参阅此问题(感谢Peter Cordes的链接和解释(。

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

  1. https://www.ibiblio.org/gferg/ldp/gcc-inline-sembly-howto.html#s5
  2. https://software.intel.com/en-us/node/694235

只有在以下情况下可以安全地使用没有clobber列表的简单内联装配块:

  1. 该块的说明不会修改ABI中定义的寄存器。因此,GPRS,堆栈计数器,标志应不受影响;如果函数中有浮点计算,则FPU/向量寄存器也没有限制。甚至内存写入也可能导致错误,因为编译器依靠已知值驻留在内存中。相比之下,可以发出INT3HLTWRMSR等指令,该指令触摸不寄存器或仅影响编译器不使用的系统寄存器。但是,大多数此类说明都是特权的,不能在用户应用程序中使用。也可以读取所有可用寄存器,只要此类读取没有副作用。
  2. 汇编器块是函数正文中的语句。在这种情况下,它必须遵守调用所选平台的惯例:如何通过函数的论点,应放置其退出代码等。该块还需要应对编译器生成的序言和具有其具有其具有其的ECILOGUE代码块的块自己关于登记册的假设。他们的代码并不严格稳定,也不是便携式,也不保证在不同的优化级别上相同。使用X86的GCC,我无法禁用序言/结语,因此仍然存在一些违反编译器假设的风险。
  3. 您可以保存所有笨拙的寄存器,然后将其恢复。这是相对容易的,因为您可以看到自己的汇编代码,并且可以判断寄存器是否通过它修改。但是,犯错,编译器将不会在这里指出。ICC 2018非常好的警告是非常好的,即使它可能只是将ASM块视为黑匣子。
  4. 您从编译器中"偷走"了一个寄存器。GCC允许使用register asm语句(不记得相同的技巧是否与其他编译器一起使用(。因此,您可以声明变量绑定到某个寄存器。请注意,这种技术会减少编译器可用于寄存器分配阶段的寄存器数量,并将降低其生成的代码质量。索要寄存器太多,编译器将无助并拒绝工作。同样,人们也不能要求登记处具有专用角色,要从编译器中删除,例如堆栈指针或程序计数器。

也就是说,带有Clobber列表的扩展asm语法提供了一个不错的选择。它将asm节从黑匣子转到一个内联内部"函数",该内部"函数"声明其自己的输入,输出和资源,它覆盖了与外部功能共享的。