前言
在C语言编程中,使用汇编指令有两种方式,一种是使用单独的汇编源文件,在最后编译的时候和其它C工程文件编译到一起,这种方式能够做到汇编函数和C函数的互相调用,但是如果希望在C语言中直接调用汇编表达式就不是那么方便了,为此我们需要使用另一种方式,即内嵌汇编。
GCC嵌入汇编语法
内嵌汇编使用一种约束好的格式来实现C调用汇编指令,GCC使用的嵌入汇编语法的基本格式如下所示
__asm__ (汇编指令模板
:输出部分
:输入部分
:破坏描述部分);
上述格式给出了嵌入汇编时可能需要使用到的基本元素,依次为汇编指令模板、输出部分、输入部分和破坏描述部分,各部分使用”:”格开,其中汇编语句模板必不可少,其他三部分可选。如果使用了后面的部分,而前面部分为空,也需要用”:”格开,相应部分内容为空。示例如下:
__asm__ __volatile__("cli": : :"memory")
在GNU C嵌入汇编中,我们常看到__asm__
后都会带上__volatile__
,__volatile__
表示编译器不要优化代码,后面的指令保留原样,volatile是它的别名。一个更加完整的嵌入汇编使用如下所示:
__asm__ __violate__ ("addl %1, %%eax;"
"movl %%eax,%0;"
: "=r" (result)
: "r" (input));
汇编指令模板
汇编语句模板由汇编语句序列组成,语句之间使用”;”、”\n”或”\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1,…,%9,其中%0表示第一个参数,%1表示第二个参数。另外,为了增强代码可读性,可以使用汇编符号名字来替代以%表示的操作数。
__asm__ __violate__ ("addl %[in], %%eax;"
"movl %%eax, %0;"
: [res] "=r" (result)
: [in]"r" (input));
其中,[res]
表示定义了一个汇编符号操作数,符号名为res,对应于输出参数"=r" (result)
;同理,[in]对应于输入参数"r" (input)
。
转义字符
汇编指令模板规定了一些特殊字符的含义:
- %%: 在输出的汇编代码中表示一个’%'字符,如上面的嵌入汇编示例中,%%eax等价于%eax,在AT&T的汇编语法中,引用寄存器需要加上%前缀;
- %= 在输出的汇编代码中生成一个唯一的数字,该数字可以代表编写的内嵌汇编程序,这相当于生成了一个本地标号;
输出部分
输出部分描述输出操作数,不同的输出操作数之间用逗号格开,每个操作数由限制字符串和C语言变量组成。每个输出操作数的限制字符串通常以”=”或者“+”开头,然后是一个字母表示对操作数类型的说明,接着是关于变量结合的约束。“=”表示被修饰的操作只具有可写属性,“+”号表示被修饰的操作数具有可读可写属性。
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=a" (x) )
上面的示例会使用eax寄存器存放pop出的值,然后存储到变量x中
输入部分
输入部分描述输入操作数,不同的操作数之间使用逗号格开,每个操作数描述符由限制字符串和C语言变量组成。输入部分描述的操作数只有只读属性,不允许修改,因此,在输入部分中,不能使用“=”或者“+”约束条件,否则编译器会报错。
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
破坏描述部分
破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外比较常用的还有“memory”和“cc”:
- memory:告知GCC编译器,嵌入汇编代码修改了内存中的值,强迫编译器在执行该汇编代码前存储所有缓存的值,在执行完汇编代码之后重新加载该值,目的是防止编译乱序;
- cc:表示嵌入汇编代码修改了状态寄存器的相关标志位。
限制字符串
限制字符的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系。限制字符有很多种。有些是与特定体系结构相关,此处列出常用的限定字符和x86中可能用到的一些常用的限定符。
限定符 | 类型 | 含义 |
---|---|---|
“r” | 寄存器 | 将变量放入通用寄存器中 |
“a” | 寄存器 | 将变量放入eax寄存器中 |
“b” | 寄存器 | 将变量放入ebx寄存器中 |
“c” | 寄存器 | 将变量放入ecx寄存器中 |
“d” | 寄存器 | 将变量放入edx寄存器中 |
“m” | 内存 | 内存变量 |
“0-9” | 匹配 | 逐一匹配操作数表达式,注意与%1-%9区分 |
示例分析
相关参考
- 《奔跑吧,Linux内核》
- 《GCC工具手册》