OK!这下好了,完全与我们的意图吻合。
如 果一个Output操作表达式的寄存器约束被指定为某个寄存器,只有当至少存在一个Input操作表达式的寄存器约束为可选约束时,(可选约束的意思是可 以从多个寄存器中选取一个,或使用非寄存器方式),比如"r"或"g"时,此Output操作表达式使用&修饰才有意义。如果你为所有的 Input操作表达式指定了固定的寄存器,或使用内存/立即数约束,则此Output操作表达式使用&修饰没有任何意义。比如:
__asm__ ("popl %0 nt"
"movl %1, %%esi nt"
"movl %2, %%edi nt"
: "=&a"(__out)
: "m" (__in1), "c" (__in2));
此例中的Output操作表达式完全没有必要使用&来修饰,因为__in1和__in2都被指定了固定的寄存器,或使用了内存方式,GCC无从选择。
但如果你已经为某个Output操作表达式指定了&修饰,并指定了某个固定的寄存器,你就不能再为任何Input操作表达式指定这个寄存器,否则会出现编译错误。比如:
__asm__ ("popl %0 nt"
"movl %1, %%esi nt"
"movl %2, %%edi nt"
: "=&a"(__out)
: "a" (__in1), "c" (__in2));
本例中,由于__out已经指定了寄存器%eax,同时使用了符号&修饰,则再为__in1指定寄存器%eax就是非法的。
反过来,你也可以为Output指定可选约束,比如"r","g"等,让GCC为其选择到底使用哪个寄存器,还是使用内存方式,GCC在选择的时候,会首先排除掉已经被Input操作表达式使用的所有寄存器,然后在剩下的寄存器中选择,或干脆使用内存方式。比如:
__asm__ ("popl %0 nt"
"movl %1, %%esi nt"
"movl %2, %%edi nt"
: "=&r"(__out)
: "a" (__in1), "c" (__in2));
本例中,由于__out指定了约束"r",即让GCC为其决定使用哪一格寄存器,而寄存器%eax和%ecx已经被__in1和__in2使用,那么GCC在为__out选择的时候,只会在%ebx和%edx中选择。
前3 个修饰符只能用在Output操作表达式中,而百分号[%]修饰符恰恰相反,只能用在Input操作表达式中,用于向GCC声明:“当前Input操作表 达式中的C/C++表达式可以和下一个Input操作表达式中的C/C++表达式互换”。这个修饰符号一般用于符合交换律运算,比如加(+),乘(*), 与(&),或(|)等等。我们看一个例子:
int main(int __argc, char* __argv[])
{
int __in1 = 8, __in2 = 4, __out = 3;
__asm__ ("addl %1, %0nt"
: "=r"(__out)
: "%r" (__in1), "0" (__in2));
return 0;
}
在 此例中,由于指令是一个加法运算,相当于等式__out = __in1 + __in2,而它与等式__out = __in2 + __in1没有什么不同。所以使用百分号修饰,让GCC知道__in1和__in2可以互换,也就是说GCC可以自动将本例的内联汇编改变为:










