由于在很多情况下,C语言无法完全代替汇编语言,比如:操作某些特殊的CPU寄存器,操作主板上的某些IO端口或者性能达不到要求等情况下,我们必须在C语言里面嵌入汇编语言,以达到我们的需求。
当需要在C语言里嵌入汇编语言段的时候,对于GNU C我们可以使用它提供的关键词“asm”来实现。先看下面一段代码:
#define nop() __asm__ __volatile__ ("nop \n\t")
这段内嵌汇编是什么意思呢?根据函数名,读者们大概也能猜到了,这个是nop函数的实现,而且这个nop是我们操作系统内核里面的库函数。让我们先学习内嵌汇编的格式,然后在下面小节里会讲解一些常用的库函数内容。
首先,介绍_ asm _ 和 _ volatile _ 这两个关键字。
_ asm _ 修饰这个是一段汇编语言,它是GCC定义的关键字asm的宏定义(#define _ asm _ asm),它用来声明一个内嵌汇编表达式。所以,任何一个内嵌汇编表达式都以它开头,它是必不可少的;如果要编写符合ANSI C标准的代码(即:与ANSI C兼容),那就要使用_ asm _;
_ volatile _ 修饰这段代码不被编译器优化,保持代码原样。这个volatile正是我们需要的,如果经过编译器优化,很有可能将我们写的程序修改,并达不到预期的执行效果了。如果要编写符合ANSI C标准的代码(即:与ANSI C兼容),那就要使用_ volatile _;
然后,该介绍内嵌汇编的语言了。 一般而言,C语言里嵌入汇编代码片段都要比纯汇编语言写的代码复杂得多。因为这里有个怎样分配寄存器、怎样与C代码中的变量融合的问题。为了这个目的,必须要对所用的汇编语言做更多的扩充,增加对汇编语言的明确指示。
C语言里的内嵌汇编代码可分为四部分,以“:”号进行分隔,其一般形式为:
指令部分:输出部分:输入部分:损坏部分
指令部分
第一部分就是汇编语言的语句本身,其格式与在汇编语言程序中使用的格式基本相同,但也有不同之处。这一部分被称为“指令部分”说明他是必须有的,而其它各部分则视具体情况而定,如果不需要的话是可以忽略的,所以在最简单的情况下就与常规的汇编语句基本相同。
指令部分的编写规则:
当指令列表里面有多条指令时,可以在一对双引号中全部写出,也可将一条或多条指令放在一对双引号中,所有指令放在多对双引号中;
- 如果是将所有指令写在一对双引号中,那么,相邻俩条指令之间必须用分号”;“或换行符(\n)隔开,如果使用换行符(\n),通常\n后面还要跟一个\t;或者是相邻两条指令分别单独写在两行中;
- 如果将指令放在多对双引号中,除了最后一对双引号之外,前面的所有双引号里的最后一条指令后面都要有一个分号(;)或(\n)或(\n\t);
在涉及到具体的寄存器时就要在寄存器名前面加上两个”%”号,以免混淆。
输出部分
第二部分,紧接在指令部分后面的是“输出部分”,用来指定当前内嵌汇编语句的输出表达式。
格式为:“操作约束”(输出表达式)
用括号括起来的部分,它用于保存当前内嵌汇编语句的一个输出值。在输出表达式内需要用(=)或(+