内联汇编中是否需要初始化所有使用的寄存器?

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