内嵌汇编

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语言表达式,本例中只有两个:resultinput,他们按照出现的顺序分别与指令操作数%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插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。

2.3. 例三