内嵌汇编
操作系统高级教程上面需要阅读Linux内核0.11的源码,其中在书《Linux内核设计的一书》第2.5节异常处理类中段服务程序挂接的部分,遇到了嵌入在C语言中的汇编代码,之前从来没有学习过汇编,因此记录下。
AT&T基础知识
内嵌汇编使用的是AT&T汇编,所以首先稍微讲解下AT&T的汇编指令的基础知识。
操作数前缀
movl $8,%eax
movl $0xffff,%ebx
int $0x80
看到在AT&T汇编中诸如"%eax"、"%ebx"之类的寄存器名字前都要加上"%";“8”、“0xffff"这样的立即数之前都要加上”$"。
源/目的操作数顺序
在Intel语法中,第一个操作数是目的操作数,第二个操作数源操作数。而在AT&T中,第一个数是源操作数,第二个数是目的操作数。
// INTEL语法
MOV EAX,8 //EAX是目的操作数, 8是源操作数
// AT&T语法
movl $8,%eax //8是源操作数 EAX是目的操作数
标识长度的操作码后缀
在AT&T的操作码后面有时还会有一个后缀,其含义就是指出操作码的大小。“l”表示长整数(32位),“w”表示字(16位),“b”表示字节(8位)。
movb %bl,%al
movw %bx,%ax
movl %ebx,%eax
movl (%ebx),%eax
GCC内嵌汇编
Linux操作系统内核代码绝大部分使用C语言编写,只有一小部分使用汇编语言编写,例如与特定体系结构相关的代码和对性能影响很大的代码。GCC提供了内嵌汇编的功能,可以在C代码中直接内嵌汇编语言语句,大大方便了程序设计。
基本行内汇编
基本行内汇编很容易理解,一般是按照下面的格式:
asm(“statements”);
在“asm”后面有时也会加上“volatile”表示编译器不要优化代码,后面的指令保留原样
asm volatile(“hlt”);
如果有很多行汇编,则每一行后要加上“\n\t” :
asm( "pushl %eax\n\