分享

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

 FigoHong 2020-07-15

在阅读本文之前,请先阅读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. output operands 的 constraint 字符串必须以 = 或 + 开始。

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

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

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

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

看个例子:

#include <stdio.h>
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方法中,我们指定的 constraint modifier 是 +,表示a原来的值在汇编代码中会被用到,所以编译器就不会改变a对应寄存器的值,所以最终结果是正确的。

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

下面是inc1:

$ gcc -O3 -S main.c && objdump --disassemble=inc1 a.out0000000000001180 <inc1>: 1180: 83 c0 01 add $0x1,%eax 1183: c3 retq

下面是inc2:

$ gcc -O3 -S main.c && objdump --disassemble=inc2 a.out0000000000001190 <inc2>:    1190:  89 f8                  mov    %edi,%eax    1192:  83 c0 01               add    $0x1,%eax    1195:  c3                     retq

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

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

希望对你有所帮助。

完。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多