如何在扩展GCC asm中正确使用多个输入和输出操作数的寄存器约束?考虑我问题的最小版本。以下是GCC中AT&T语法的简短扩展asm代码:
int input0 = 10;
int input1 = 15;
int output0 = 0;
int output1 = 1;
asm volatile("mov %[input0], %[output0]\t\n"
"mov %[input1], %[output1]\t\n"
: [output0] "=r" (output0), [output1] "=r" (output1)
: [input0] "r" (input0), [input1] "r" (input1)
:);
printf("output0: %d\n", output0);
printf("output1: %d\n", output1);
根据https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html,语法似乎是正确的。然而,我可能忽略了某些东西或犯了一些微不足道的错误,但出于某种原因我看不到。
GCC 5.3.0 p1.0(没有编译器参数)的输出为:
output0: 10
output1: 10
期望的输出是:
output0: 10
output1: 15
在GDB中查看它的结果是:
这段代码将eax加载为input0,edx加载为input1。然后用eax覆盖edx,用edx覆盖eax,使它们相等。最后将它们写回到output0和output1中。如果使用内存约束(=m)而不是寄存器约束(=r)来输出,则会得到预期的输出,并且汇编代码看起来更合理。
=&r
来处理输出操作数,因为该寄存器在汇编模板的最后一条指令之前被修改。_GCC_会认为它可以将该寄存器作为输入再次使用。&
将防止早期占位符分配的寄存器被用作输入寄存器。 - Michael Petchg
约束,而不是r
。由于输出仅定义为寄存器,并且模板中的mov
指令可以接受至少一个内存或立即值操作数,因此使用g
可以让编译器有机会执行其他优化。g
约束的文档说明为_允许任何寄存器、内存或立即整数操作数,但不包括非通用寄存器_。 - Michael Petchg
作为输入操作数约束,编译器应该能够意识到某些输入实际上是常量(立即)值,这应该可以实现一些代码简化。如果您使用 GCC 编译并使用-O3
优化级别,可以更好地看到这些优化。 - Michael Petch"=r,r,rm,rm", "=r,rm,r,rm" : "g,g,ri,ri", "g,ri,g,ri"
。 - Ross Ridge