我正在尝试使用ICC 2018编译以下代码:
__asm {
mov ebx, xx ;xx address to registers
}
Run Code Online (Sandbox Code Playgroud)
其中xx的类型为int16.这是我函数中的第一条指令.
我使用上面的汇编代码得到以下警告:警告#13212:在需要堆栈对齐的函数中引用ebx
令人惊讶的是,当我用eax或esi替换ebx时,我看到警告消失了.我无法理解为什么我只看到ebx的问题,据我所知,ebx和eax都有相同的架构(32位寄存器).
此外,当我使用ICC 2013编译相同的代码时,我没有看到警告.
谁能帮我解决这个警告?
谢谢!
如果需要额外的对齐,所选平台上的编译器(ICC,因为它模仿 MSVC 的行为)使用 EBX 来保存原始堆栈指针值。因此您无法安全地覆盖它。程序的行为将变得不确定。编译器警告只是告诉你这一点。
为了帮助保存/恢复受汇编块影响的所有寄存器,建议使用所谓的破坏列表的扩展语法。您的示例使用 MSVC 样式__asm{...}语法。在 MSVC 风格的语法中,编译器会检测您触摸的寄存器并为您保存/恢复它们。ICC 还支持带有 clobber 列表的扩展 asm 的类似于 GCC 的表示法:asm("...":::)。它还支持更简单的 GCC asm("..."),无需破坏列表部分。有关更多详细信息,请参阅此问题(感谢 Peter Cordes 提供链接和解释)。
当我学习使用 clobber 列表时,我发现有用的文档(实际上我一直在使用它,因为不可能记住它对人类不友好的语法):
没有破坏列表的简单内联汇编块只能在以下情况下安全使用:
INT3、等指令HLT,WRMSR这些指令要么不接触任何寄存器,要么只影响编译器不使用的系统寄存器。然而,大多数此类指令都是特权指令,不能在用户应用程序中使用。人们还可以读取所有可用的寄存器,前提是此类读取没有副作用。register asm语句执行此操作(不记得相同的技巧是否适用于其他编译器)。因此,您可以声明变量绑定到某个寄存器。请注意,这种技术会减少编译器在寄存器分配阶段可用的寄存器数量,这会降低其生成的代码质量。要求太多的寄存器,编译器将束手无策,拒绝工作。同样,不能要求编译器取消具有专用作用的寄存器,例如堆栈指针或程序计数器。也就是说,asm带有破坏列表的扩展语法提供了一个很好的替代方案。它将一个asm部分从一个黑盒子变成了一个内联内部“函数”,它声明了自己的输入、输出和它覆盖的资源,这些资源与外部函数共享。