GCC内联装配中的0..9约束有什么作用?

xyhw6mcr  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(101)

The manual表示:
允许使用与指定的操作数编号匹配的操作数。如果在同一替代项中将数字与字母一起使用,则数字应排在最后。
我不知道这是什么意思。
示例代码:

asm volatile("swap %0" : "=r" (value) : "0" (value));

(Stack Overflow的inline-assembly tag wiki有其他文档和指南的链接)

mfuanj7w

mfuanj7w1#

这就像是将"+r"(value)输入/输出操作数拆分为单独的操作数(使用单独的C变量)用于输入和输出,同时仍然强制它们选择同一个寄存器。
因此,无论寄存器%0选取什么,%1都将是相同的寄存器。**操作数从左到右计数,从0开始。**对于%0%1当匹配的约束引用较早的操作数时,
我只见过它与匹配输出约束的输入约束一起使用,这样你就可以在模板中省略它,而不会有编译器期望你的asm模板从一个reg复制到另一个reg的风险。

**对于"+r"(value),对输入和输出使用相同的C变量更容易。**为此匹配约束是毫无意义的复杂性。

也许"+r"只是在后来的gcc版本中添加的,因为您确实看到了在读/写操作数更容易时使用的匹配约束。
如果在同一备选项中,数字与字母一起使用,则数字应排在最后。”
这是考虑一个约束的可能性,它给编译器提供了多个约束的选择。例如,"rm"让编译器选择寄存器或内存。
x86上的"a0"会选择EAX或与操作数0相同的寄存器。我不确定这在什么时候会有用。也许它可以与一个早期乱码一起使用,告诉编译器这个输入与某个输出在同一个寄存器中仍然是可以的?但也可以选择任何寄存器,就像"r0"一样?
显然,如果使用"r0"这样的约束,则(通常)需要在asm模板中显式使用%1(或它具有的任何数字或命名操作数),因为您不知道编译器将在给定周围代码和优化级别的情况下选择哪个位置。
在调试约束时,使用包含约束的asm注解会很有用,包括您要对其进行假设的约束。

asm ("swap %0    # other operand: %1  "  : "=r"(output) : "0"(input));

结果asm将为%0%1打印相同的寄存器名两次。它在更复杂的情况下变得更有趣。
就像您使用"r"(input)一样,您的代码可能碰巧可以工作,因为编译器确实为输入和输出选择了相同的reg(因为没有早期的clobber)。但是当它为output选择了不同的reg而中断时,(并期望input的原始值仍在其寄存器中未改变),您可以通过查看约束选择了哪些reg来调试它,然后意识到您假设它们会选择相同的reg,但没有告诉编译器这一点。

相关问题