汇编和c语言 编译的区别,c语言内嵌汇编代码之constraint modifier中 = 和 的区别

在阅读本文之前,请先阅读gcc的相关文档,确保对如何在c中使用汇编语言有个基本的认识。

文档地址为:

https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Using-Assembly-Language-with-C.html#Using-Assembly-Language-with-C

1. = 和 + 只能用于 output operands,不能用于 input operands。

2. output operands 的 constraint 字符串必须以 = 或 + 开始。

3. = 和 + 都表示对应的 output operand 有写操作。

4. = 表示的可写,是告诉编译器在执行这条asm语句时,该 output operand 原来的值不会被用到,所以它占用的寄存器或内存在写操作发生之前可以被随便使用。

5. + 表示的可写,是告诉编译器在执行这条asm语句时,该 output operand 原来的值会被用到,所以它占用的寄存器或内存不能被随便使用,否则可能会导致在该 output operand 被使用时,原数据被覆盖了。

6. + 是在 = 的基础上,对编译器做的更严格的限制。

看个例子:#include int inc1(int a){asm('add $1, %0' : '=r' (a));return a;}int inc2(int a){asm('add $1, %0' : '+r' (a));return a;}int main(int argc, char *argv[]){printf('inc1: %d\n', inc1(1));printf('inc2: %d\n', inc2(1));}

这两个inc方法本应该都返回2,但实际却不是,我们执行看下:$ gcc -O3 main.c && ./a.outinc1: 1998320153inc2: 2

由上可见,inc1方法返回的是一个莫名其妙的值(其实每次执行该程序,inc1返回的值都不同),这是因为inc1中指定的 constraint modifier 是 =,它表示在汇编代码里不会用到a原来的值,所以编译器可能会在add汇编指令执行之前,用到了a对应的寄存器,导致其原数据被覆盖,又可能它根本就没初始化a对应的寄存器为我们传入的值,总之,最终结果是错误的。

而在inc2方法中,我们指定的 constraintmodifier 是 +,表示a原来的值在汇编代码中会被用到,所以编译器就不会改变a对应寄存器的值,所以最终结果是正确的。

我们再来看下两个方法对应的汇编代码,进一步确认下。

下面是inc1:$ gcc -O3 -S main.c && objdump --disassemble=inc1 a.out0000000000001180 :1180: 83 c0 01 add $0x1,%eax1183: c3 retq

下面是inc2:$ gcc -O3 -S main.c && objdump --disassemble=inc2 a.out0000000000001190 :1190: 89 f8 mov %edi,%eax1192: 83 c0 01 add $0x1,%eax1195: c3 retq

通过对比我们可以发现,inc1方法里就根本没有初始化a对应的寄存器eax为a原来的值,这导致了在执行add操作时,a对应的寄存器中是一个随机值,所以最终结果是错误的。

通过上面的例子,我想你们应该已经明白了 = 和 + 的具体区别。

希望对你有所帮助。

完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值