GCC 内联汇编

语法格式

1
2
3
4
5
6
7
asm volatile
{
汇编语句模板
: 输出部分
: 输入部分
: 破坏描述部分
}
  • asm volatile
    表示后面的代码为内嵌汇编,asm__asm__ 的别名。volatile 表示编译器不能优化代码。
  • 汇编语句模板
    由汇编语句序列构成,语句之间用;, \n, \n\t 分隔. 指令中的操作数可以用占位符引用 C 语言变量. 指令中使用占位符表示的操作数总被视为 long 型(4 个字节)。使用的操作符可以作用与字或字节,默认作用于低字节。可以用 hb 修饰,如 %h1.
  • 输出部分
    格式为"=?"(var) 的形式,var 可以是任意内存变量(输出结果会存到这个变量中),? 一般是下面这些标识符。
    • a, b, c, d, S, D 分别代表 eax, ebx, ecx, edx, esi, edi,寄存器
    • r 代表上面这些寄存器中任意一个(哪个闲置用哪个)
    • m 内存
    • i 立即数(常量,只用于输入操作数)
    • g, 寄存器,内存,立即数(由编译器决定)
      在汇编中,用 %序号 代表这些输入/输出操作数,序号从 0 开始。为了与操作数分离,寄存器用 标出, 如 %%eax.
  • 输入操作数
    格式为 ?(var), ? 除了可以是上面这些标识符,还可以是输出操作数的序号,表示用 var 初始化该输出操作数。
  • 破坏描述部分
    在汇编代码中修改,又没有在输入/输出列表中列出的寄存器,这样 gcc 就不会擅自使用这些寄存器,用 memory 表示在内联汇编中修改了内存,之前缓存在寄存器中的内存变量需要重新读取。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
int a=1, b=2, c=0;
// add
// c = a + b
asm(
"addl %2, %0" // 1
: "=g"(c) // 2
: "0"(a), "g"(b) // 3
: "memory"); // 4
printf("现在c是:%d\n", c);
return 0;
}