简介

内联汇编是在c语言代码中插入一段汇编语言,这在一些特殊的场合如操作系统中经常使用。有些时候我们想加快速度或者进行某些特殊的操作就可以使用内联汇编。

语法

关键字: asm


asm volatile(
"movl %eax, %ebx"
);

其中,volatile的含义是告诉编译器这段代码不需要优化,原封不动的让他执行。

语法:

asm(
汇编语言模板
: output operands /*可选*/
: input operands /*可选*/
: options /*可选*/
);

可以只有output operands或只有input operands。但是如果有options,那么前面两个冒号都要打.

options表示我们最多使用哪些寄存器。

汇编模板

可以使用AT&T语法,也可以使用intel语法(没有测试过)。下面以AT&T模板作为例子。

它的语法和和汇编语言完全类似,同样是寄存器用%,立即数用$, 内存访问用()

注意

  • 如果有多行汇编语句,那么语句与语句之间要用\n\t分隔开
  • 如果使用了%0,%1等标识,那么寄存器就需要用两个%%标识
int a = 1;
asm volatile(
"movl %0, %%eax\n\t"
"pushl %%eax\n\t"
:"a"(a)
);

输出和输入部分

他们的格式都是 "restriction"(value),其中restriction表示这个变量要使用哪个寄存器或者表示内存或者是立即数。而value就是外带的变量。

如果是输出部分,在restricttion前还要加个等号。如 “=a”(output)

在定义了输入和输出部分之后,就可以把这些变量用于汇编语句中了。我们可以用%0,%1…%9表示变量。也就是说最多有是个输入输出部分。例如

int input = 1;
int output = 1;
asm volatile(
"addl %1, %0"
:"=r"(output)
:"r"(input)
);

上面就是一个简单的1+1并且把值赋到output中。output是第0个,input第第一个,所以%0表示output,%1表示input.

限制

输入输出部分前面的限制有很多,这里列举一些常用的

限制 作用
a 表示 eax,ax,ah,al
b 表示 ebx, …
c 表示 ecx, …
d 表示 edx, …
S 表示 esi
D 表示 edi
r 指定任意一个寄存器
m 表示内存
p 表示操作数是一个指针
X 可以是任意类型
i 立即数
数字0,1,2,… 表示这个操作数和前面的某个操作数相同,一般在输入和输出在同一个变量时使用
f 浮点数
& 避免使用同一个寄存器

访问内存方式:

int input = 0x7fffffc;
asm volatile(
"movl %%eax, (%0)"
: "r"(input)
);

或者
result = 0;

input = 1;

asm volatile ("addl %1,%0":"+r"(result):"m"(input));

一个具体应用

void (*handler)();
handler = myproc()->tf->handler;
uint addr = (uint)*handler;
myproc()->tf->esp -= 4;
asm volatile(
"movl %0, (%1)\n\t"
: "r"(myproc()->tf->eip), "r"(myproc()->tf->esp)
);
myproc()->tf->eip = addr;

这段代码的作用是位于内核态时跳转到某一个函数,并且结束之后返回,asm中就是将返回地址存入栈中。