你能看到这篇文章说明你肯定是知道AT&T语法是个什么东西,但是要注意,下文所示示例都是拓展内联汇编,而不是基本内联汇编,代码示例在Ubuntu环境下演示

ATT完整语法如下,asm volatile ("汇编代码":output:intput:"命令单词"),包含2个单词,一个小括号,3个冒号,其中volatile,“汇编代码”,output,intput,"命令单词"均可以省略

output:汇编代码中的寄存器的值给C语言变量
intput :汇编代码中要使用C语言变量中

示例1:
下面的代码格式为asm("汇编代码":output),演示了如下2步操作
1)将十进制立即数555给eax(汇编代码,冒号前的部分)
2)将eax里的值给var2(output,冒号后的部分)

#include "stdio.h"
void main(){int var2=0;printf("%d\n",var2);//打印0asm("movl $555,%%eax":"=a"(var2));printf("%d\n",var2);//打印555
}

"movl $555,%%eax"(冒号前的部分)的解释:

movl:小写L表示555是4个字节,movb表示1个字节,movw表示2字节,当然了,在本例中555用1个字节肯定报错的
KaTeX parse error: Expected 'EOF', got '&' at position 5: :在AT&̲T语法中,如果是一个立即数,则…```修饰
%%:在AT&T拓展内联汇编中,如果使用寄存器,则前面必须加两个百分号修饰

"=a"(var2)(冒号后的部分)的解释:

=:表示只写,当然了既然是从寄存器中拿值放到C变量中,肯定是只写,这不是废话吗?没错,的确是废话,但是这个等号不得不加。。。也可能是我的GCC版本问题,反正我的GCC是必须要写这个等号的
a:表示eax,或者ax,或者al,那么同理,b表示ebx,bx,或者bl,以此类推
():小括号必须写,且里面的内容是一个C语言变量
var2:C语言变量

示例2:
下面的代码格式为asm("汇编代码"::input),演示了如下2步操作
1)将var2的值给eax
2)将eax的值给ebx

#include "stdio.h"
void main(){int var2=0;printf("%d\n",var2);asm("movl %%eax,%%ebx"::"a"(var2));printf("%d\n",var2);
}

"a"(var2)的解释:将C语言变量中的var2的值给eax寄存器
"movl %%eax,%%ebx"的解释:将eax中的值给ebx
当然了,对于本示例2,是看不见结果的,因为没有打印ebx,所以代码如下改动,看下面的示例

示例3:
下面的代码格式为asm("汇编代码":output:input),演示了如下2步操作
1)将var2的值给eax
2)将eax的值给ebx
3)将ebx的值给var3

#include "stdio.h"
void main(){int var2=666;int var3=0;printf("var3=%d\n",var3);//打印0asm("movl %%eax,%%ebx":"=b"(var3):"a"(var2));printf("var3=%d\n",var3);//打印666
}

我们发现做简单的传值操作,必须通过寄存器,这样做在步骤上还是有些复杂,所以下面的示例直接内存地址操作,而不通过寄存器中转

示例4:
下面的代码格式为asm("汇编代码"::input),示例同样是将var3的值给var2

#include "stdio.h"
void main(){int var2=666;int var3=0;printf("var3=%d\n",var3);asm("movl %0,%1"::"a"(var2),"m"(var3));printf("var3=%d\n",var3);
}

%0,%1的解释:%0表示input中的第0个参数,也就是"a"(var2),%1表示input中的第1个参数,也就是"m"(var3)
"m"(var3)的解释:m表示取var3的内存地址(指针)

注:下面的写法是错误的,因为我们知道,mov操作数,至少要有一个寄存器,而不能都是内存地址

asm("movl %0,%1"::"m"(var2),"m"(var3));

示例5(memory):
下面的代码格式为asm("汇编代码"::input:"memory"),与示例4基本一样,只不过最后多了一个"memory",下面只是代码写法,打印结果是无法看出来的

#include "stdio.h"
void main(){int var2=666;int var3=0;printf("var3=%d\n",var3);asm("movl %0,%1"::"a"(var2),"m"(var3):"memory");printf("var3=%d\n",var3);
}

memory的解释:memory表示告诉gcc,内存被修改了,但是它真正的意义在于:清空寄存器缓存(看到这里java的朋友是不是有些熟悉?),如果此处不只有memory,还有很多其他参数,比如下面这些
cc:表示告诉gcc,修改了标志寄存器asm("movl %0,%1"::"a"(var2),"m"(var3):"cc");
al:表示告诉gcc,修改了eax,ax,al寄存器,asm("movl %0,%1"::"a"(var2),"m"(var3):"al");等等还有很多参数,不一一列举了,因为我也不是全都知道

为什么要告诉gcc这些东西?因为正常情况下我们写C语言编译之后,GCC知道该如何对C语言中的变量进行资源(寄存器和内存)分配,但是我们嵌入了汇编语言,而且嵌入的汇编语言,还可能通过系统调用,调用其他系统函数,这就导致GCC根本不知道我们是否修改过资源,所以必须告知GCC我们修改了资源

关于memory: 刚才说过,它真正的意义在于:清空寄存器缓存,这句话的意思是说在多线程处理器情况下,如果不带memory参数,那么各自的线程将执行自己线程中的变量副本,这些副本是从父线程复制过来的,加上memory之后,每次使用变量,都会清空寄存器缓存,然后从主存中获取数据,而hotspot JVM的底层实现就是使用该参数实现内存屏障,说的直白一点,就是java中的volatile和synchronized关键字的实现

示例6(volatile):
下面的代码格式为asm volatile ("汇编代码"::input:"memory"),与示例5基本一样,只不过多了一个volatile,下面只是代码写法,打印结果是无法看出来的

#include "stdio.h"
void main(){int var2=666;int var3=0;printf("var3=%d\n",var3);asm volatile ("movl %0,%1"::"a"(var2),"m"(var3):"memory");printf("var3=%d\n",var3);
}

volatile的解释:告诉GCC,不要优化我写的汇编代码(注意,是汇编代码,而不是C代码),这样GCC在编译阶段就不会进行汇编代码的编译器重排序了,同时也会告诉编译器可以优化C代码,但是要被volatile隔开,volatile上面的N多代码你可以优化,volatile下面的代码你也可以优化,但是volatile上面的代码不可以优化到volatile下面,同样的volatile下面的代码你也不能优化到上面,我们可以管这种操作叫做编译器屏障

如果你想获得更详细的信息,可以参考SUN公司1998年94303-4900《x86 Assembly Language Reference Manual》文档

C语言-ATT拓展内联汇编(ATT/GCC)相关推荐

  1. 【ATT 与 Intel】汇编与C语言相互调用及内联汇编

    目录 一.ATT 与 Intel 二.函数调用的约定 三.C语言调用汇编程序 四.汇编程序调用C语言 五.内联汇编 5.1.基本asm格式 5.2.扩展asm格式 5.3.使用占位符来替代寄存器名称 ...

  2. 一步步编写操作系统 77 内联汇编与ATT语法简介

    内联汇编 之前和大家介绍过了一种汇编方法,就是C代码和汇编代码分别编译,最后通过链接的方式结合在一起形成可执行文件. 另一种方式就是在C代码中直接嵌入汇编语言,强大的GCC无所不能,咱们本节要学习的就 ...

  3. C语言内联汇编使用方法

    GCC内联汇编 一.基本语法 asm volatile ( assembler template: output operands /* optional */: input operands /* ...

  4. C 语言内联汇编介绍

    文章目录 为什么要用内联汇编 内联汇编的基本要素 语法 汇编语句模板 操作数 输出部分和输入部分 操作数约束 常用约束 寄存器操作数约束 内存操作数约束 (m) 匹配(数字)约束 为什么要用内联汇编 ...

  5. C语言中递归什么时候能够省略return引发的思考:通过内联汇编解读C语言函数return的本质...

    C语言中递归什么时候能够省略return引发的思考:通过内联汇编解读C语言函数return的本质 事情的经过是这种,博主在用C写一个简单的业务时使用递归,因为粗心而忘了写return.结果发现返回的结 ...

  6. C语言进阶——内联汇编

    内联函数 在 C 语言中,我们可以指定编译器将一个函数代码直接复制到调用其代码的地方执行.这种函数调用方式和默认压栈调用方式不同,我们称这种函数为内联函数.有点像宏. 优点:内联函数降低了函数的调用开 ...

  7. 汇编程序设计与计算机体系结构软件工程师教程笔记:内联汇编与宏

    <汇编程序设计与计算机体系结构: 软件工程师教程>这本书是由Brain R.Hall和Kevin J.Slonka著,由爱飞翔译.中文版是2019年出版的.个人感觉这本书真不错,书中介绍了 ...

  8. 最牛X的GCC 内联汇编

    导读 正如大家知道的,在C语言中插入汇编语言,其是Linux中使用的基本汇编程序语法.本文将讲解 GCC 提供的内联汇编特性的用途和用法.对于阅读这篇文章,这里只有两个前提要求,很明显,就是 x86 ...

  9. linux arm gcc 内联汇编参考手册

    关于本文档 GNU C 编译器为 ARM 精简指令系统处理器提供了在 C 代码中内嵌汇编的功能.这种非常酷的特性提供了一些 C 代码没有的功能,比如手工优化软件关键代码.使用相关的处理器指令. 本文假 ...

最新文章

  1. mysql学习资料_一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了
  2. 爬虫笔记10Scrapy-框架
  3. 24个笔画顺序表_小学一年级语文26个汉语拼音字母要点+田字格儿歌,赶紧给孩子看...
  4. Cannot read property 'scrollWidth' of null
  5. C++:Hello C++!
  6. 愚人节主题的微信公众号图文排版有哪些搞怪素材?
  7. 什么是pid控制算法_智能车运动控制 ——PID简介
  8. CubieBoard7开发板(基于S700芯片)基于安卓系统固件编译
  9. 电脑作为sntp服务器配置
  10. 元核云赋能银行业,智能双录产品助力银保业务合规高效响应
  11. 怎么给div加背景图片
  12. 基于Robopeak触摸屏和官方摄像头的树莓派照相机
  13. 对角矩阵、对称矩阵、单位向量、正交矩阵
  14. 光盘复制-DVD光盘复制格式剖析
  15. 2022年9月青少年软件编程(图形化)等级考试试卷--三级--跳高比赛
  16. Modern Robotics串联机器人常见的奇异构型
  17. 电商图片采集-免费批量电商图片采集软件
  18. String字符串删除空格的七种方式
  19. 「红米 2A 标准版」闪屏救砖、更正官方线刷救砖工具
  20. web前端设计与开发期末作品 用DIV CSS技术设计的网上书城网页与实现制作(大一Web课程设计)

热门文章

  1. ReentrantLock实现原理
  2. Java中判断一个字符串全为数字和字母
  3. mysql接口教程_接口测试教程 - xmysql 介绍
  4. gitlab批量新增用户
  5. Oracle收集用户的权限
  6. linux下和htm的运行,嵌入式LINUX下CGI与HTML网页之间的通信
  7. CircularFifoQueue队列API
  8. JAVA多线程共享变量的可见性
  9. webstore忽略指定的文件夹显示
  10. SpringCloudConfig配置中心读取本地配置文件