IA32寄存器与x86-64寄存器的区别
IA32寄存器
一个IA32CPU包含一组8个存储32位值的通用寄存器,这些寄存器用来存储整数数据和指针:
| 31-0 | 15-0 | 15-8 | 7-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-63 | 0-31 | 0-15 | 8-15 | 0-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支持的基于栈的方法来实现。
IA32寄存器与x86-64寄存器的区别的更多相关文章
- linux版本信息以及x86与x86_64的区别
一 x86.x86_64.AMD64 x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种 ...
- [转帖]Linux系统下x86和ARM的区别有哪些?
Linux系统下x86和ARM的区别有哪些? https://www.cnblogs.com/alantu2018/p/9209143.html 其实界限 越来越小了.. 问题: 最近在用三星的一款i ...
- 32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用
32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用 一丶32位(x86也称为80386)与8086(16位)汇编的区别 1.寄存器的改变 AX 变为 EAX 可以这样想,16位通 ...
- Windows内核开发-9-32位和64位的区别
Windows内核开发-9-32位和64位的区别 32位的应用程序可以完美再64位的电脑上运行,而32位的内核驱动无法再64位的电脑上运行,或者64位的驱动无法在32位的应用程序上运行.这是为什么呢. ...
- < IOS > X-code 5.1 x86 - 64 编译问题
关于xcode 5.1 x86 - 64 编译问题 坐等了N久,终于IOS 7.1 发布了,作为一个果粉,忍不住第一时间升级了.结果用设备测试的时候,出问题了,一直检测不到设备,哈哈,纠结了半 ...
- Win7系统32位和64位的区别
Win7系统32位和64位的区别已经是一个老话题了,可是还是有很多朋友不明白.这两者到底有什么区别呢?下面本文与大家通俗的介绍下Win7系统32位和64位的区别,其他一些深入的理论讲述,大家可以看看文 ...
- x86—EFLAGS寄存器详解(转载)
鉴于EFLAGS寄存器的重要性,所以将这一部分内容从处理器体系结构及寻址模式一文中单独抽出另成一文,这部分内容主要来自Intel Developer Mannual,在后续的内核系列中遇到的许多和EF ...
- x86—EFLAGS寄存器详解[转]
鉴于EFLAGS寄存器的重要性,所以将这一部分内容从处理器体系结构及寻址模式一文中单独抽出另成一文,这部分内容主要来自Intel Developer Mannual,在后续的内核系列中遇到的许多和EF ...
- 浅淡Windows7 32位与64位/x86与x64的区别
看到有很多会员问到底是选Windows7 x86,还是选x64.这里简单的谈一下这这两种系统的区别. 简单的说x86代表32位操作系统 x64代表64位操作系统. 简单的判断电脑是否支持64位操作系 ...
- windows游戏编程X86 (内存)寄存器相关的基本概念
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22446971 作者:jadeshu 邮箱: jades ...
随机推荐
- Python 面向对象2
静态方法 静态方法相当于函数,可以不创建对象直接引用 如果在类里面用静态方法,相当于函数,可以不创建对象,直接是用类里面的方法,你就当它是函数. 静态方法名义上归类管理,实际上静态方法访问不了类或实例 ...
- 【Telnet】使用Telnet协议连接到远程Shell执行脚本
介绍 本文介绍如何通过Telnet协议连接到远程Shell,执行脚本,并获取执行结果: 相关文章: <[Jsch]使用SSH协议连接到远程Shell执行脚本>http://www.cnbl ...
- 【linux】之相关命令
防火墙 ) 重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off ) 即时生效,重启后失效 开启: service iptables s ...
- ruby发送邮件方法
#encoding:utf-8require 'mail'def send_email sum,fail,case_path,name,receive smtp = { :address => ...
- SQL 递归树 子父节点相互查询
if object_id('[tb]') is not null drop table [tb] go create table [tb]([modeid] int,modename varchar( ...
- php生成curl命令行
e.g. curl “http://localhost/other/serverInfo.php?dd=ddd” -H “Host:localhost” -H “Connection:keep-ali ...
- SQL 常用的命令 (转)
地址:http://www.cnblogs.com/longly/p/6030609.html 设置SQL语句所用的字符编码:set names UTF8; 判断指定的数据库是否存在:DROP DAT ...
- LINUX 磁盘如何分区
fdisk -l 可以查看当前磁盘 假设未分配磁盘为/dev/sdb size=10G fdisk /dev/sdb (m for help) 按照提示应该可以分区成功,注意一点 一个磁 ...
- Mysql的视图、存储过程、函数、索引全解析
视图是查询命令结果构成的一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集合,并可以当作表来查询使用. 1创建视图 --格式:C ...
- python 日期相关的各种操作总结
用 Python 做项目时,经常会遇到与日期转换相关,日期计算相关的功能,动不动就要去查python手册,感觉麻烦,因此把自己常用的一些东西,总结了一下,总体说来到目前为止遇到如下一些需求: 1. 用 ...