内联汇编中是否需要初始化所有使用的寄存器?
Is it necessary to initialize all the used registers in inline assembly?
我正在使用 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 将生成上面的代码。是不是说所有的寄存器都需要先初始化才能在内联汇编中使用?
将我的评论移到 'Answer' 这样这个问题就可以关闭了。
为了防止编译器将寄存器重复用于输入和输出,您可以使用 early clobber 约束(例如 =&r (x)
),它会通知编译器寄存器与参数关联的是
written before the instruction is finished using the input operands.
虽然这可能是一件好事(因为它减少了在调用您的 asm 之前必须可用的寄存器数量),但它也可能导致问题(如您所见)。因此,要么确保在写入输出之前已完成使用所有输入,要么使用 &
告诉编译器不要进行此优化。
为了完整起见,我还要指出,使用内联汇编通常是 bad idea。
我正在使用 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 将生成上面的代码。是不是说所有的寄存器都需要先初始化才能在内联汇编中使用?
将我的评论移到 'Answer' 这样这个问题就可以关闭了。
为了防止编译器将寄存器重复用于输入和输出,您可以使用 early clobber 约束(例如 =&r (x)
),它会通知编译器寄存器与参数关联的是
written before the instruction is finished using the input operands.
虽然这可能是一件好事(因为它减少了在调用您的 asm 之前必须可用的寄存器数量),但它也可能导致问题(如您所见)。因此,要么确保在写入输出之前已完成使用所有输入,要么使用 &
告诉编译器不要进行此优化。
为了完整起见,我还要指出,使用内联汇编通常是 bad idea。