前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c语言内嵌汇编代码之constraint modifier中 & 的作用

c语言内嵌汇编代码之constraint modifier中 & 的作用

作者头像
KINGYT
发布2019-10-14 16:30:08
7880
发布2019-10-14 16:30:08
举报

在阅读本文之前,请先阅读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. & 的作用是告诉编译器,在这条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:

$ gcc -O3 main.c && ./a.out
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 试下:

#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()); }

编译后执行:

$ gcc -O3 main.c && ./a.out
3

看到没,这次就对了,因为 & 使编译器不会再为a和b分配相同的寄存器。

再看下汇编代码确认下:

$ gcc -O3 main.c && objdump --disassemble=f a.out
0000000000001170 <f>:
    1170:  b8 01 00 00 00         mov    $0x1,%eax
    1175:  89 c2                  mov    %eax,%edx
    1177:  83 c2 01               add    $0x1,%edx
    117a:  89 c0                  mov    %eax,%eax
    117c:  01 d0                  add    %edx,%eax
    117e:  c3                     retq

由上可以看到,这次a使用的寄存其是eax,b使用的寄存器是edx,所以没有了寄存器冲突,所以最终结果是正确的。

希望对你有所帮助。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux内核及JVM底层相关技术研究 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档