1. 格式
内联汇编的基本格式如下:
1 | __asm__ __volatile__("汇编语句":输出部分:输入部分:破坏描述部分); |
其中:
__asm__
为内联汇编语句关键词。通常也会使用别名asm来代替。__volatile__
表示编译器不要优化代码,指令保持原样。通常也会使用别名volatile来代替。- 汇编语句必不可少,语法和汇编语言程序中基本相同,多个汇编语句需要使用
;
、\n
或\n\t
隔开。 - 输出部分可以缺省。
- 输入部分可以缺省。
- 破坏描述部分可以缺省。破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有”memory”。
2. 举例
2.1. 例一
1 | __asm__ __violate__ ("movl %1,%0" : "=r" (result) : "m" (input)); |
其中:
movl %1,%0
是指令模板,%0
和%1
代表指令的操作数,称为占位符,内嵌汇编靠它们将C语言表达式与指令操作数相对应。指令模板后面用小括号括起来的是C语言表达式,本例中只有两个:result
和input
,他们按照出现的顺序分别与指令操作数%0
,%1
对应;注意对应顺序:第一个C表达式对应%0
;第二个表达式对应%1
,依次类推,操作数至多有10个,分别用%0
,%1
….%9
表示。在每个操作数前面有一个用引号括起来的字符串,字符串的内容是对该操作数的限制或者说要求。
result
前面的限制字符串是=r
,其中=
表示result
是输出操作数,r
表示需要将result
与某个通用寄存器相关联,先将操作数的值读入寄存器,然后在指令中使用相应寄存器,而不是result
本身,当然指令执行完后需要将寄存器中的值存入变量result
,从表面上看好像是指令直接对result
进行操作,实际上GCC做了隐式处理,这样我们可以少写一些指令。input
前的m
表示操作数在内存中,而不是在寄存器中。
2.2. 例二
1 | __asm__ __volatile__("cli": : :"memory") |
cli部分不用多介绍。memory描述符告知编译器:
- 不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕
- 不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变,因此GCC插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。