在阅读本文之前,请先阅读gcc的相关文档,确保对如何在c中使用汇编语言有个基本的认识。 文档地址为: https://gcc./onlinedocs/gcc-9.2.0/gcc/Using-Assembly-Language-with-C.html#Using-Assembly-Language-with-C 1. & 只能用于 output operands,不能用于 input operands。 2. & 的作用是告诉编译器,在这条asm语句中的汇编代码完成对该 output operand 的写操作之后,后面的汇编代码还是会使用到 input operands 的值,即:告诉编译器不要为该 output operand 和 input operands 分配相同的寄存器或内存空间,否则会导致该 output operand 的写操作覆盖掉 input operands 原来的值,这样使得后面汇编代码再用到 input operands 的值时,使用的是被覆盖过后的值。 看个例子: #include <stdio.h>
int f() { int a = 1; int b; int c;
asm('mov %2, %0\n\t' 'add $1, %0\n\t' 'mov %2, %1' : '=r'(b), '=r'(c) : 'r'(a));
return b + c; }
int main(int argc, char *argv[]) { printf('%d\n', f()); } 理论上f方法返回的值应该是3,但实际上却是4:
这是因为a和b使用了相同的寄存器,导致第二个mov语句在使用a的值时,读到的是2,所以最终结果变成了4。 看下其汇编代码: $ gcc -O3 main.c && objdump --disassemble=f a.out 0000000000001170 <f>: 1170: b8 01 00 00 00 mov $0x1,%eax 1175: 89 c0 mov %eax,%eax 1177: 83 c0 01 add $0x1,%eax 117a: 89 c2 mov %eax,%edx 117c: 01 d0 add %edx,%eax 117e: c3 retq 在该汇编代码中,第一行是给a赋值为1,第二行是将a的值拷贝到b里,第三行是对b做加1处理,第四行是将a的值拷贝到c里,第五行是将b和c的值相加,第六行是返回最终的结果。 由汇编代码可以看到,a和b的确使用的相同的寄存器eax,所以最终结果是错误的。 下面我们加上 & 这个 constraint modifier 试下:
编译后执行: $ gcc -O3 main.c && ./a.out 3 看到没,这次就对了,因为 & 使编译器不会再为a和b分配相同的寄存器。 再看下汇编代码确认下:
由上可以看到,这次a使用的寄存其是eax,b使用的寄存器是edx,所以没有了寄存器冲突,所以最终结果是正确的。 希望对你有所帮助。 完。 |
|