__asm__ __volatile__内嵌汇编用法简述 在阅读C/C++原码时经常会遇到内联汇编的情况,下面简要介绍下__asm__ __volatile__内嵌汇编用法。因为我们华清远见教学平台是ARM体系结构的,所以下面的示例都是用ARM汇编。

带有C/C++表达式的内联汇编格式为:

__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);

其中每项的概念及功能用法描述如下:

1、 __asm__

__asm__是GCC 关键字asm 的宏定义:

#define __asm__ asm

__asm__或asm 用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是必不可少的。

2、Instruction List

Instruction List 是汇编指令序列。它可以是空的,比如:__asm__ __volatile__(""); 或 __asm__ ("");都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。但并非所有Instruction List 为空的内联汇编表达式都是没有意义的,比如:__asm__ ("":::"memory");

就非常有意义,它向GCC 声明:“内存作了改动”,GCC 在编译的时候,会将此因素考虑进去。 当在"Instruction List"中有多条指令的时候,可以在一对引号中列出全部指令,也可以将一条 或几条指令放在一对引号中,所有指令放在多对引号中。如果是前者,可以将每一条指令放在一行,如果要将多条指令放在一行,则必须用分号(;)或换行符(\n)将它们分开. 综上述:(1)每条指令都必须被双引号括起来 (2)两条指令必须用换行或分号分开。

例如: 在ARM系统结构上关闭中断的操作

int disable_interrupts (void)
{
unsigned long old,temp;
__asm__ __volatile__("mrs %0, cpsr\n"
"orr %1, %0, #0x80\n"
"msr cpsr_c, %1"
: "=r" (old), "=r" (temp)
:
: "memory");
return (old & 0x80) == 0;
}

3. __volatile__

__volatile__是GCC 关键字volatile 的宏定义

#define __volatile__ volatile

__volatile__或volatile 是可选的。如果用了它,则是向GCC 声明不允许对该内联汇编优化,否则当 使用了优化选项(-O)进行编译时,GCC 将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。

4、 Output

Output 用来指定当前内联汇编语句的输出

例如:从arm协处理器p15中读出C1值

static unsigned long read_p15_c1 (void)
{
unsigned long value;
__asm__ __volatile__(
"mrc p15, 0, %0, c1, c0, 0 @ read control reg\n"
: "=r" (value) @编译器选择一个R*寄存器
:
: "memory");
#ifdef MMU_DEBUG
printf ("p15/c1 is = %08lx\n", value);
#endif
return value;
}

5、 Input

Input 域的内容用来指定当前内联汇编语句的输入Output和Input中,格式为形如“constraint”(variable)的列表(逗号分隔)

例如:向arm协处理器p15中写入C1值

static void write_p15_c1 (unsigned long value)
{
#ifdef MMU_DEBUG
printf ("write %08lx to p15/c1\n", value);
#endif
__asm__ __volatile__(
"mcr p15, 0, %0, c1, c0, 0 @ write it back\n"
:
: "r" (value) @编译器选择一个R*寄存器
: "memory");
read_p15_c1 ();
}

6.、Clobber/Modify

有时候,你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希望GCC在编译时能够将这一点考虑进去。那么你就可以在Clobber/Modify域声明这些寄存器或内存。这种情况一般发生在一个寄存器出现在"Instruction List",但却不是由Input/Output操作表达式所指定的,也不是在一些Input/Output操作表达式使用"r"约束时由GCC 为其选择的,同时此寄存器被"Instruction List"中的指令修改,而这个寄存器只是供当前内联汇编临时使用的情况。

例如:

__asm__ ("mov R0, #0x34" : : : "R0");

寄存器R0出现在"Instruction List中",并且被mov指令修改,但却未被任何Input/Output操作表达式指定,所以你需要在Clobber/Modify域指定"R0",以让GCC知道这一点。

因为你在Input/Output操作表达式所指定的寄存器,或当你为一些Input/Output操作表达式使用"r"约束,让GCC为你选择一个寄存器时,GCC对这些寄存器是非常清楚的——它知道这些寄存器是被修改的,你根本不需要在Clobber/Modify域再声明它们。但除此之外, GCC对剩下的寄存器中哪些会被当前的内联汇编修改一无所知。所以如果你真的在当前内联汇编指令中修改了它们,那么就最好在Clobber/Modify 中声明它们,让GCC针对这些寄存器做相应的处理。否则有可能会造成寄存器的不一致,从而造成程序执行错误。

如果一个内联汇编语句的Clobber/Modify域存在"memory",那么GCC会保证在此内联汇编之前,如果某个内存的内容被装入了寄存器,那么在这个内联汇编之后,如果需要使用这个内存处的内容,就会直接到这个内存处重新读取,而不是使用被存放在寄存器中的拷贝。因为这个 时候寄存器中的拷贝已经很可能和内存处的内容不一致了。

这只是使用"memory"时,GCC会保证做到的一点,但这并不是全部。因为使用"memory"是向GCC声明内存发生了变化,而内存发生变化带来的影响并不止这一点。

例如:

int main(int __argc, char* __argv[])
{
int* __p = (int*)__argc;
(*__p) = 9999;
__asm__("":::"memory");
if((*__p) == 9999)
return 5;
return (*__p);
}

本例中,如果没有那条内联汇编语句,那个if语句的判断条件就完全是一句废话。GCC在优化时会意识到这一点,而直接只生成return 5的汇编代码,而不会再生成if语句的相关代码,而不会生成return (*__p)的相关代码。但你加上了这条内联汇编语句,它除了声明内存变化之外,什么都没有做。但GCC此时就不能简单的认为它不需要判断都知道 (*__p)一定与9999相等,它只有老老实实生成这条if语句的汇编代码,一起相关的两个return语句相关代码。

另外在linux内核中内存屏障也是基于它实现的include/asm/system.h中

# define barrier() _asm__volatile_("": : :"memory")

主要是保证程序的执行遵循顺序一致性。呵呵,有的时候你写代码的顺序,不一定是最终执行的顺序,这个是处理器有关的。

转载于:https://blog.51cto.com/19831028/433739

__asm__ __volatile__内嵌汇编用法简述相关推荐

  1. asm volatile内嵌汇编用法

    带有C/C++表达式的内联汇编格式为: __asm__ __volatile__("InSTructiON List" : Output : Input : Clobber/Mod ...

  2. 结合实例分析arm指令集中的adds指令与arm内嵌汇编

    qq截图进来的图全部丢失了........郁闷...... 以下是ffmpege0.11.1源码中的一个函数,稍微做了点修改 注意:编译器我arm-linux-gcc4.4.1,其他的编译器请读者自行 ...

  3. __asm__ __volatile__ GCC的内嵌汇编语法 ATT汇编语言语法(Z)

    此文在网上到处转载,已不知原出处,我也将之记录在此,并改正其中的一些小笔误. 开 发一个OS,尽管绝大部分代码只需要用C/C++等高级语言就可以了,但至少和硬件相关部分的代码需要使用汇编语言,另外,由 ...

  4. __asm__ __volatile__ 嵌入式内嵌汇编语法解构

    __asm__ __volatile__ 嵌入式内嵌汇编语法解构 带有C/C++表达式的内联汇编格式为: __asm__ __volatile__("Instruction List&quo ...

  5. GCC在C语言中内嵌汇编 asm __volatile__

    在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可 ...

  6. ATT汇编语言与GCC内嵌汇编简介

    AT&T汇编语言与GCC内嵌汇编简介 1 AT&T 与INTEL的汇编语言语法的区别 1.1大小写 1.2操作数赋值方向 1.3前缀 1.4间接寻址语法 1.5后缀 1.6指令 2 G ...

  7. GCC如何编译内嵌汇编代码

    内核代码绝大部分使用C  语言编写,只有一小部分使用汇编语言编写,例如与特定体系结构相关的代码和对性能影响很大的代码.GCC提供了内嵌汇编的功能,可以在C代码中直接内嵌汇编语言语句,大大方便了程序设计 ...

  8. GCC的内嵌汇编语法 ATT汇编语言语法

    __asm__ __volatile__ GCC的内嵌汇编语法 AT&T汇编语言语法(一) 2007年05月09日 12:36 开 发一个OS,尽管绝大部分代码只需要用C/C++等高级语言就可 ...

  9. 转载:asm volatile GCC的内嵌汇编语法 ATT汇编语言语法

    asm volatile  GCC的内嵌汇编语法 AT&T汇编语言语法 目录 asm volatile  GCC的内嵌汇编语法 AT&T汇编语言语法 1 Overview 2.  GC ...

最新文章

  1. Java中对象引用的机制,及特点
  2. 使用 ChatterBot 库制作一个聊天机器人
  3. opencv 霍夫曼变换 直线提取
  4. CUDA ---- device管理
  5. 九月免费手账分享-【奶油星云】
  6. php微信小程序获取用户信息,微信小程序获取openid及用户信息的方法
  7. 前端学习(2361):下拉刷新的学习
  8. 第四节:HTML5给表单带来的新标签、新属性、新类型
  9. 已知先序和中序得出后序
  10. php中的全局异常,tp5 API 自定义全局异常处理(中)
  11. 记事本如何运行python代码_记事本写代码怎么运行
  12. 创建三维零件的DH坐标系
  13. matlab分析excel数据,基于MATLAB的EXCEL数据计算与分析
  14. 西门子PLC 和v90 伺服变频器G120通讯
  15. 单层感知机(Single Layer Perceptron)详解
  16. PDF模板查找关键字坐标
  17. echarts图表应用
  18. html手机打不开是什么意思,html是什么意思
  19. Android UI设计 下拉菜单Spinner用法 动态添加删除Spinner菜单项
  20. 学 Python 的乐园,坚持一年,值了!

热门文章

  1. java 画笔跟swing组件_「软帝学院」:2019思维最清晰的java学习路线
  2. 【MyBatis框架】mapper配置文件-foreach标签
  3. 关于redis的持久化
  4. centos7搭建单机kafka集群
  5. scrapy爬取汽车之家宝马5系图片
  6. 2017年度IT168技术卓越奖名单:服务器类
  7. Spring Framework 官方文档学习(三)之Resource
  8. 网站开发综合技术 HTML
  9. (Command Pattern)命令模式
  10. 设计模式:单件模式(Singleton Pattern)