专栏首页Linux内核及编程语言底层相关技术研究c语言内嵌汇编代码之InputOperands使用时的注意事项

c语言内嵌汇编代码之InputOperands使用时的注意事项

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

文档地址为:

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


1. 编译器认为asm语句中的 input operands 只是用来读数据的,不会被修改,所以当该asm语句执行完毕之后,后面的代码如果还有地方使用 input operands,则不管在asm语句的汇编代码中有没有修改过 input operands,后面代码使用的 input operands 的值都是原来的值。

2. 如果想要告知编译器 input operands 在asm语句的汇编代码中有被修改过,只能通过将 input operands 绑定到 output operands 的形式。其实本质上编译器还是通过 output operands 得知数据被修改了的,只是此时由于 input operands 和 output operands 使用的是同一寄存器或内存地址,所以相当于编译器也间接得知了 input operands 的修改。

下面来看个具体例子:

#include <stdio.h>

int inc1(int src) {
  asm("add $1, %0" : : "r" (src));
  return src;
}

int inc2(int src) {
  asm("add $1, %0" : "=r" (src) : "0" (src));
  return src;
}

int main(int argc, char *argv[]) {
  printf("inc1: %d\n", inc1(1));
  printf("inc2: %d\n", inc2(1));
}

该例子中的inc方法都是将src的值加1,然后再返回,所以理论上来说最终的输出都应该是2。

但我们执行看下结果:

$ gcc main.c && ./a.out
inc1: 1
inc2: 2

由上可以看到,inc1的结果是1,这是因为编译器认为src只是asm语句的输入,所以它不会被修改,所以在return的时候直接返回了原值。

看下其对应的汇编代码:

$ gcc -O3 main.c && objdump --disassemble=inc1 a.out
0000000000001180 <inc1>:
    1180:  89 f8                  mov    %edi,%eax
    1182:  83 c7 01               add    $0x1,%edi
    1185:  c3                     retq

和我们想的一样,return时返回的就是原值。

inc2方法的返回结果是正确的,因为我们把输入绑定到了输出,编译器通过输出可以知道数据被修改过了。

同样看下其汇编代码:

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

的确是正确的逻辑。

通过上面的例子我们可以看到,编译器认为asm语句的输入参数是只读的,所以我们在asm语句的汇编代码里也不要去修改输入参数的值,如果非要修改,一定要通过某种方式告知编译器,防止最终的逻辑错误。

本文分享自微信公众号 - Linux内核及JVM底层相关技术研究(ytcode),作者:wangyuntao

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Git示例教程 - 如何使用git rebase命令

    现在我们想要将topic分支上的ABC提交重新rebase到最新的master分支上,可以执行如下命令:

    wangyuntao
  • GCC 优化级别

    1. gcc中指定优化级别的参数有:-O0、-O1、-O2、-O3、-Og、-Os、-Ofast。

    wangyuntao
  • Linux tcp/ip 源码分析 - connect

    由第一篇文章可以知道,sock->ops->connect指向的方法为inet_stream_connect。

    wangyuntao
  • .NET面试题系列[6] - 反射

    在面试中,通常会考察反射的定义(操作元数据),可以用反射做什么(获得程序集及其各个部件),反射有什么使用场景(ORM,序列化,反序列化,值类型比较等)。如果答得...

    s055523
  • Zookeeper 集群角色、原理

    集群中的 server 分为三种角色:leader, follower, observer。

    斯武丶风晴
  • 解决连接oracle报ORA-01034和ORA-27101的错误

    我本机安装的数据库版本是ORACLE 11G R2,今天连接数据库时,报如下错误:

    williamwong
  • Java Web Servlet过滤器

      过滤器就是可以对浏览器向jsp,servlet,html等这些web资源发出请求和

    Hongten
  • 树状数组理论基础

      树状数组(binary indexed trees,二进制索引树),最早由Peter M. Fenwick于1994年以“A New Data Struct...

    用户2965768
  • Python实现控制台密码星号输入

    Note:这种方法很安全,但是看不到输入的位数,让人看着有点不太习惯,而且没有退格效果。

    周小董
  • 如何用Python做情感分析?

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地。本文帮助你一步步用Python做出自己的情感分析结果,难道你不想试试看?

    王树义

扫码关注云+社区

领取腾讯云代金券