reactos中涉及的GNU gas 汇编

分析环境reactos0.3.4 ,i386体系]

Reactos中涉及的汇编

这几天在看HAL中关于IRQL的实现部分基于PIC(8259a)的,相关文件位于hal\halx86\generic\irq.s,这个文件是用汇编语言写的。一开始以为是用nasm来编译的,后来打开makefile.auto才发现也是用GCC来编译的。大概看了看这个文件中的语法格式,有个疑问,感觉这个文件很像intel的汇编格式写的,但是又发现有些定义又不同比如

intel 汇编语法用dd、dw 和 db 来声明一个内存变量。但是这个文件中是用.long、.int 和 .byte来声明的。而引用寄存器时前面又没有加“%”号,搞不懂。。。。。。。。。为什么reactos不统一使用一种风格的汇编语法,经过分析后发现在Reactos中,存在两种风格的汇编格式文件,一种文件使用的是GNU gas 汇编器来编译,而另一种使用的是nasm汇编器,那些以“.S”结尾的汇编文件一般是用GAS来编译的,而以“.ASM”一般是用nasm编译,使用nasm汇编的文件基本上集中在freeldr\bootsect里,而其他的一般就使用了GAS汇编。(还有一些c文件中内部潜入了at&t的汇编格式和intel的汇编格式)

nasm汇编语法基本上类似intel的语法,而一般在linux中大家都使用GAS的是AT&T的语法格式。GAS 的现代版本支持intel汇编语法指令,因此允许在 GAS 中使用 Intel 语法。一开始的时候在想,gas是如何区分那些文件时intel格式的汇编,而那些是AT&T的汇编?也许可以通过命令行参数。不过后来在看hal\halx86\generic\irq.s时突然发现最上面有条

.intel_syntax noprefix

原来是用这条指令表示使用intel语法格式替代AT&T语法格式,不过这种方式感觉仅仅是替代指令语法格式。

下面就ReactOS中相关的gas汇编intel语法格式做一个总结

内存有效地址
intel格式
section:[base+index*scale+displacement]

section:段前缀
base:基址寄存器
index:变址寄存器
scale:可以取值1,2,4,8。如果不指定scale 值,则默认值为1
displacement:偏移量


宏定义
gas中的宏定义和c语言中的宏定义相同如(可能又叫符号常量吧):

#define KPCR_IRQL     0x24
#define PCR           ds:[0xFFDFF000]

mov ecx, PCR[KPCR_IRQL]         // 这种表达有点类似结构变量的访问

// 经过宏代换后
mov ecx, ds:[0xFFDFF000+0x24]

变量定义
汇编语言中可以给存储单元取符号名,也可以不取符号名。当给存储单元取符号名时,则可通过该符号名来访问其对应的存储单元;当不给存储单元取符号名时,则可通过存储单元的偏移量(有效地址)来访问它。

[变量名:]  数据类型符  表达式1[, 表达式2, …, 表达式n]  //注释

如:
PICInitTable: .short 0x20
              .byte 0x11
第一个可以用地址来访问,后面的一个可以用PICInitTable+2访问


其他变量类型说明:

 

编译定义符
说明
语法
例子
.byte
字节定义 expr(8bit数值)
.byte expr {, }
.byte 25, 0x11, 031, 'A
.hword
半字定义expr (16bit数值)
.hword expr {, }
.hword 2, 0xFFE0
.short
作用同.hword
.short expr {, }
.short 257
.word
字长定义expr (32bit数值)
.word expr {, }
.word 144511, 0x11223
.int
作用同.word
.int expr {, }
.int 21
.long
作用同.word
.long expr {, }
.long 1923, 0b10010101
.ascii
定义字符串expr(非零结束符)
.ascii expr {, }
.ascii "Ascii text is here"
.asciz
定义字符串expr(以0为结束符)
.asciz expr {, }
.asciz "Zero Terminated Text"
.string
作用同 .asciz
.string expr {, }
.string "My Cool String\n"
.quad
定义一个大的数expr (向上分成8bit的数存放)
.quad expr {, }
.quad 0xDAFADAFA911
.octa
定义一个大的数expr(向上分成16bit的数存放)
.octa expr {, }
.octa 0xFEDCBA987654321
.float
定义一个32bit IEEE 浮点数expr
.float expr {, }
.float 0f3.14, 0f359.2e11
.single
作用同.float
.single expr {, }
.single 0f12341243.14E2
.double
定义64bit IEEE浮点数expr(浮点数)
.double expr {, }
.double 0f2E1
.fill
 
 
 
 
size长度value填充repeat次。size缺省为1, value缺省为 0.
.fill repeat {, size}
 
{, value}
.fill 32, 4, 0xFFFFFFFF
 
 
 
 
 
 
.zero
0填充内存(size个字节)
.zero size
.zero 400
.space
value填充size个字节,value缺省为0
.space size {, value}
.space 25, 0b11001100
.skip
作用同.space
.skip size {, value}
.skip 22


数组的定义:
KiI8259MaskTable:
    .long 0                             /* IRQL 0 */
    .long 0                             /* IRQL 1 */
    .long 0                             /* IRQL 2 */
    .long 0                             /* IRQL 3 */
    .long 0xFF800000                    /* IRQL 4 */
    .long 0xFFC00000                    /* IRQL 5 */
    .long 0xFFE00000                    /* IRQL 6 */
    .long 0xFFF00000                    /* IRQL 7 */
    .long 0xFFF80000                    /* IRQL 8 */
    .long 0xFFFC0000                    /* IRQL 9 */
    .long 0xFFFE0000                    /* IRQL 10 */
    .long 0xFFFF0000                    /* IRQL 11 */
    .long 0xFFFF8000                    /* IRQL 12 */
    .long 0xFFFFC000                    /* IRQL 13 */
    .long 0xFFFFE000                    /* IRQL 14 */
    .long 0xFFFFF000                    /* IRQL 15 */
    .long 0xFFFFF800                    /* IRQL 16 */
    .long 0xFFFFFC00                    /* IRQL 17 */
    .long 0xFFFFFE00                    /* IRQL 18 */
    .long 0xFFFFFE00                    /* IRQL 19 */
    .long 0xFFFFFE80                    /* IRQL 20 */
    .long 0xFFFFFEC0                    /* IRQL 21 */
    .long 0xFFFFFEE0                    /* IRQL 22 */
    .long 0xFFFFFEF0                    /* IRQL 23 */
    .long 0xFFFFFEF8                    /* IRQL 24 */
    .long 0xFFFFFEF8                    /* IRQL 25 */
    .long 0xFFFFFEFA                    /* IRQL 26 */
    .long 0xFFFFFFFA                    /* IRQL 27 */
    .long 0xFFFFFFFB                    /* IRQL 28 */
    .long 0xFFFFFFFB                    /* IRQL 29 */
    .long 0xFFFFFFFB                    /* IRQL 30 */
    .long 0xFFFFFFFB                    /* IRQL 31 */

数组的访问
    mov eax, KiI8259MaskTable[eax*4] // 可以在eax中存放数组的索引号


符合变量定义
将 .rept 与 .endr之间的语句count次如:

简单的重复:

GenericIRQ:

.rept 7
    .long GenericIRQ                    /* IRQ 0-7 */
.endr

复杂的重复:
.rept 7
    .long GenericIRQ                    /* IRQ 0-7 */
    .byte 0xFB
.endr

其他关键字
.global
关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用。比如一些全局函数和全局变量。
.globl
_HalpInitPICs@0

.func
产生名为label调试信息段。省略label信息段名使用name
.func name {, label}
.func
HalpInitPICs@0

.endfunc //.func结束定义符

 c/c++风格的条件编译
#if
#else
#endif


函数名称解释
__
symbol@N
__stdcall函数(其参数占用N字节)


@
symbol@N
__fastcall函数(其参数占用N字节)

__symbol
__cdecl函数

比如在irq.s中有这样的定义:

.globl _HalpInitPICs@0            // 表明这个函数被定义成__stdcall调用规则,没有参数
.func
HalpInitPICs@0
_HalpInitPICs@0:

又如:

.globl @HalClearSoftwareInterrupt@4   // 表明这个函数被定义成__fastcall调用规则,参数4个字节
.func @HalClearSoftwareInterrupt@4, @HalClearSoftwareInterrupt@4
@HalClearSoftwareInterrupt@4:

还有:
.globl _HalpApcInterrupt  // 表明这个函数被定义成__cdecl调用规则
.func HalpApcInterrupt

函数调用约定
       __cdecl约定:函数参数按照从右到左的顺序入栈,由函数调用者把参数弹出栈来清理堆栈。因此,实现可变参数的函数只能使用__cdecl调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。
       
        __fastcall约定:函数参数中,将从左边开始的两个大小不大于4个字节(一个DWORD)的参数,分别存放在ECX和EDX寄存器,其余的参数仍旧按照自右向左顺序压栈传送,被调用的函数在返回前清理传送参数的堆栈。

__stdcal约定:函数参数按照从右到左的顺序入栈,由被调用的函数在返回前清理栈上的参数,此时要求函数参数个数固定。因此被调用的函数可以在返回前用一条 ret n 指令直接清理栈上的参数。

 [如需转载请注明出处:(雄)blog.csdn.net/mickey139]

posted @ 2008-10-04 21:32  BinSys  阅读(995)  评论(0编辑  收藏  举报