我正在使用gcc测试简单的内联汇编代码。而且我发现以下代码的结果意外:
#include <stdio.h>
int main(void) {
unsigned x0 = 0, x1 = 1, x2 = 2;
__asm__ volatile("movl %1, %0;\n\t"
"movl %2, %1"
:"=r"(x0), "+r"(x1)
:"r"(x2)
:);
printf("%u, %u\n", x0, x1);
return 0;
}
打印结果为1, 1
,而不是预期的1, 2
。然后,我用-S
选项编译了代码,发现gcc生成的代码为
movl %eax, %edx;
movl %edx, %eax;
%0
和%2
使用相同的寄存器,为什么?
我想让gcc生成
movl %eax, %edx;
movl %ecx, %eax;
如果我在输入约束中添加"0"(x1)
,则gcc将生成上面的代码。这是否意味着所有寄存器都需要在内联汇编中使用之前进行初始化?
答案 0 :(得分:2)
将我的评论移至“答案”,以便可以关闭此问题。
要防止编译器为输入和输出重用寄存器,可以使用early clobber约束(例如=&r (x)
),该约束通知编译器与该寄存器关联的寄存器。参数是
在使用输入操作数完成指令之前编写。
虽然这可能是一件好事(因为它减少了在调用asm之前必须提供的寄存器数量),但它也会引起问题(如您所见)。因此,请确保在写入输出之前已完成使用所有输入,或使用&
告诉编译器不要执行此优化。
为完整起见,我还要指出,使用内联汇编通常是bad idea。