IA32寄存器与x86-64寄存器的区别

来源:互联网 发布:js正则验证数字和字母 编辑:程序博客网 时间:2024/05/16 01:22

IA32寄存器

一个IA32CPU包含一组8个存储32位值的通用寄存器,这些寄存器用来存储整数数据和指针:

31-015-015-87-0使用惯例%eax%ax%ah%al调用者保存%ecx%cx%ch%cl调用者保存%edx%dx%dh%dl调用者保存%ebx%bx%bh%bl被调用者保存%esi%si无无被调用者保存%edi%di无无被调用者保存%ebp%bp无无不得占用%esp%sp无无不得占用

第一行数字代表其下方对应的寄存器存储的位数,例如寄存器%eax是32位的,从0到31正好32位,%ax是16位寄存器,从0到15正好是16位。注意,如果读取%eax的8-15位则读取的是%ah,其他情况类似。

程序可以独立地读取前四个寄存器的2个低位字节,即可以独立地读取前四个寄存器的0-7位和8-15位。而后四个则不能。表中无代表对应位置无寄存器。

其中0-7位和8-15位的寄存器可以存储一个字节的数据,如char型数据;0-15位的寄存器可以存储两个字节的数据,如short类型的数据;0-31位的寄存器可以存储四个字节的数据,如int型数据。还有如long类型的数据可以用寄存器%edx存储高32位,用%eax存储低32位的数据。

寄存器%eax,%ecx和%edx由调用者保存,而寄存器%ebx,%esi和%edi由被调用者保存。就是说如果一个函数调用另一个函数,由于寄存器数量有限(只有8个),如果函数中参数或局部变量过多,寄存器就不够用了,所以要把寄存器中保存的值保存到栈中防止数据丢失,然后该寄存器就可以用来存储别的数据了,那把这个活交给谁呢?所以就规定前三个寄存器由调用者保存,接下来的三个由被调用者保存。

而寄存器%ebp和%esp有特殊用途,%ebp保存帧指针(基地址,base pointer),%esp保存栈指针(stack pointer)。程序栈中每调用一个函数就会创建一个栈帧,栈是向下增长的。寄存器%ebp保存一个栈帧的起始地址(即基地址),一般来说函数中的局部变量靠%ebp加上偏移量寻找;寄存器%esp保存指向栈顶的指针。

寄存器%eax和寄存器%edx也有特殊用途,%eax一般用于保存函数的返回值,也用来保存64位数据的低32位;%edx用来保存64位数据的高32位。

CPU中只有这八个寄存器吗?显然不是,IA32还有8个80位的浮点寄存器。还有很多特殊用途的寄存器,比如控制寄存器%cr0,%cr2,%cr3和%cr4;还有debug寄存器%dr0,%dr1,%dr2和%dr3;段寄存器%cs, %ds, %es, %fs, %gs和%ss;还有全局和局部描述符表的虚拟寄存器%gdtr(global descriptor table register)和%ldtr(local descriptor table register)。这些寄存器在操作系统中都是很重要的,在这里不再赘述,想知道的可以上网查查。

x86-64寄存器

x86-64最初由AMD提出并命名,将IA32扩展到64位并且新增加了8个寄存器,到达16个通用目的寄存器。这大大提高了机器的性能。扩展到64位可以大大扩大机器可以使用的虚拟地址空间的大小。x86-64的寄存器无论只在数量上还是在使用方法上都与IA32有很大不同,先看下表:

0-630-310-158-150-7使用惯例%rax%eax%ax%ah%al保存返回值%rbx%ebx%bx%bh%bl被调用者保存%rcx%ecx%cx%ch%cl第4个参数%rdx%edx%dx%dh%dl第3个参数%rsi%esi%si无%sil第2个参数%rdi%edi%di无%dil第1个参数%rbp%ebp%bp无%bpl被调用者保存%rsp%esp%sp无%spl栈指针%r8%r8d%r8w无%r8b第5个参数%r9%r9d%r9w无%r9b第6个参数%r10%r10d%r10w无%r10b调用者保存%r11%r11d%r11w无%r11b调用者保存%r12%r12d%r12w无%r12b被调用者保存%r13%r13d%r13w无%r13b被调用者保存%r14%r14d%r14w无%r14b被调用者保存%r15%r15d%r15w无%r15b被调用者保存

上表的格式说明和IA32一样,可以看到x86-64共有16个寄存器(16行),可以独立访问前四个寄存器的8-15位,而其他寄存器不可以。

最后一列说明该寄存器的使用惯例,可以看到如果函数参数不超过6个则可以保存在寄存器中而不用转存在内存中,如果函数的参数的个数超过6个则其余的参数须保存在栈中。

还可以看见,x86-64并没有帧指针,而只用栈指针(%rsp),作为替代,x86-64对栈位置的引用相对于栈指针(而IA32相对于帧指针%ebp),大多数函数在调用开始时分配所需要的整个栈存储,并保持栈指针指向固定的位置。函数最多可以访问当前栈指针值128个字节的栈上的存储空间,也就是说x86-64的程序可以使用当前栈指针之外128字节范围内的数据。

在IA32中栈指针会随着值的压入和弹出不断前后移动,所以在IA32中通过帧指针(%ebp)来访问栈中的数据。但是x86-64过程中的栈帧通常有固定的大小,在函数开始时通过减少栈指针(%rsp)来设置。在调用过程中栈指针保持固定的位置,使得可以通过相对于栈指针的偏移量来访问数据。因此就不再需要帧指针了,可以把%rbp用作通用寄存器。

x86-64主要特性如下:

1.指针和长整数是64位长(IA32的指针是32位长),整数算术运算支持8,16,32,和64位数据类型。

2.通用目的寄存器由8个扩展到16个。

3.许多程序状态都保存在寄存器中而不是栈上(因为寄存器数量多了)。整型和指针类型的过程参数(最多6个)通过寄存器传递。减少了对栈的访问,从而提高了效率。

4.如果可能,条件操作用条件传送指令实现,这样会比传统的分支代码得到更好的性能。

5.浮点操作用面向寄存器指令集来实现,而不用基于IA32支持的基于栈的方法来实现。

1 0
原创粉丝点击