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