学习永无止境!!
分类: LINUX
2009-11-11 14:36:15
gcc中的内嵌汇编语言(Intel i386平台)
一.声明
虽然Linux的核心代码大部分是用C语言编写的,但是不可避免的其中还是有一部分是用汇编语言写成的。有些汇编语言代码是直接写在汇编源程序中的,特别是Linux的启动代码部分;还有一些则是利用gcc的内嵌汇编语言嵌在C语言程序中的。这篇文章简单介绍了gcc中的内嵌式汇编语言,主要想帮助那些才开始阅读Linux核心代码的朋友们能够更快的入手。
写这篇文章的主要信息来源是GNU的两个info文件:as.info和gcc.info,如果你觉得这篇文章中的介绍还不够详细的话,你可以查阅这两个文件。当然,直接查阅这两个文件可以获得更加权威的信息。如果你不想被这两篇文档中的一大堆信息搞迷糊的话,我建议你先阅读一下这篇文章,然后在必要时再去查阅更权威的信息。
二.简介
在Linux的核心代码中,还是存在相当一部分的汇编语言代码。如果你想顺利阅读Linux代码的话,你不可能绕过这一部分代码。在Linux使用的汇编语言代码中,主要有两种格式:一种是直接写成汇编语言源程序的形式,这一部分主要是一些Linux的启动代码;另一部分则是利用gcc的内嵌式汇编语言语句asm嵌在Linux的C语言代码中的。这篇文章主要是介绍第二种形式的汇编语言代码。
首先,介绍一下as支持的汇编语言的语法格式。大家知道,我们现在学习的汇编语言的格式主要是Intel风格的,而在Linux的核心代码中使用的则是AT&T格式的汇编语言代码,应该说大部分人对这种格式的汇编语言还不是很了解,所以我觉得有必要介绍一下。
--AT&T and Intel 汇编语法对照
寄存器命名:
AT&T: %eax
Intel: eax
AT&T 语法源地址在左侧,目的地址在右侧与Intel 方式语法相反
将eax值传入ebx
AT&T: movl %eax, %ebx
Intel: mov ebx, eax
AT&T 语法在立即数前有前缀$.
AT&T: movl $0x0h, %eax
Intel: mov eax,0x0h
AT&T 语法在操作符后跟表示操作数类型的后缀b,w,l分别表示字节,字,双字,相当于伪操作符ptr,如果不加的话GAS会guess
AT&T: movw %ax, %bx
Intel: mov bx, ax
内存寻址方式
AT&T: immed32(basepointer,indexpointer,indexscale)
Intel: [basepointer + indexpointer*indexscale + immed32]
地址计算公式为:
immed32 + basepointer + indexpointer * indexscale
直接寻址
AT&T: _a
Intel: [_a]
间接寻址
AT&T: (%eax)
Intel: [eax]
相对寻址
AT&T: _variable(%eax)
Intel: [eax + _variable]
AT&T: _array(,%eax,4)
Intel: [eax*4 + array]
C 代码: *(p+1) p定义为char *
AT&T: 1(%eax) where eax has the value of p
Intel: [eax + 1]
结构体数组寻址,结构体长度为8,下标存于eax,结构体内偏移地址存于ebx,_array为结构体数组首地址
AT&T: _array(%ebx,%eax,8)
Intel: [ebx + eax*8 + _array]
函数内部实现交换
内嵌汇编语法如下:
__asm__(
汇编语句模板:
输出部分:
输入部分:
破坏描述部分)
共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用“:”隔开,相应部分内容为空。例如:
__asm__ __volatile__(
"cli":
:
:"memory")