x86架构.docx
《x86架构.docx》由会员分享,可在线阅读,更多相关《x86架构.docx(16页珍藏版)》请在冰豆网上搜索。
x86架构
x86
x86是一个指令集架构家族,最早由英特尔在“Intel8086”CPU上开发出来。
该系列较早期的处理器名称是以数字来表示80x86。
由于以“86”作为结尾,包括Intel8086、80186、80286、80386以及80486,因此其架构被称为“x86”。
由于数字并不能作为注册商标,因此Intel及其竞争者均在新一代处理器使用可注册的名称,如Pentium。
现时英特尔把x86-32称为IA-32,全名为“IntelArchitecture,32-bit”;不过,由于x86包括16位处理器,这样的命名也出现麻烦。
目录
∙1历史
∙2设计
o2.1运作模式
▪2.1.1实模式
▪2.1.216位保护模式
▪2.1.332位保护模式
▪2.1.4系统管理模式
▪2.1.5虚拟86模式
o2.2功能扩充
▪2.2.1MMX和之后
▪2.2.23DNow!
▪2.2.3SSE
▪2.2.4SSE2
▪2.2.5SSE3
▪2.2.6SSE4
o2.3寻址模式
o2.4x86暂存器
▪2.4.116位
▪2.4.232位
▪2.4.364位
▪2.4.4128位
▪2.4.5256比特
▪2.4.6512位
▪2.4.7暂存器结构
o2.5虚拟
∙3x86指令格式
o3.1指令前缀
o3.2指令码
o3.3ModR/M与SIB
o3.4位移与立即数
∙4生产商
∙5参见
历史
x86架构于1978年推出的Intel8086中央处理器中首度出现,它是从Intel8008处理器中发展而来的,而8008则是发展自Intel4004的。
8086在三年后为IBMPC所选用,之后x86便成为了个人电脑的标准平台,成为了历来最成功的CPU架构。
其他公司也有制造x86架构的处理器,计有Cyrix(现为威盛电子所收购)、恩益禧集团、IBM、IDT以及Transmeta。
Intel以外最成功的制造商为AMD,其早先产品Athlon系列处理器的市场份额仅次于IntelPentium。
8086是16位处理器;直到1985年32位的80386的开发,这个架构都维持是16位。
接着一系列的处理器表示了32位架构的细微改进,推出了数种的扩充,直到2003年AMD对于这个架构发展了64位的扩充,并命名为AMD64。
后来英特尔也推出了与之兼容的处理器,并命名为Intel64。
两者一般被统称为x86-64或x64,开创了x86的64位时代。
值得注意的是英特尔早在1990年代就与惠普合作提出了一种用在安腾系列处理器中的独立的64位架构,这种架构被称为IA-64。
IA-64是一种崭新的系统,和x86架构完全没有相似性;不应该把它与x86-64或x64弄混。
设计
x86架构是重要地可变指令长度的CISC(复杂指令集电脑,ComplexInstructionSetComputer)。
字组(word,4位组)长度的存储器访问允许不对齐存储器地址,字组是以低位字节在前的顺序存储在存储器中。
向后兼容性一直都是在x86架构的发展背后一股驱动力量(设计的需要决定了这项因素而常常导致批评,尤其是来自对手处理器的拥护者和理论界,他们对于一个被广泛认为是落后设计的架构的持续成功感到不解)。
但在较新的微架构中,x86处理器会把x86指令转换为更像RISC的微指令再予执行,从而获得可与RISC比拟的超标量性能,而仍然保持向前兼容。
x86架构的处理器一共有四种执行模式,分别是真实模式,保护模式,系统管理模式以及虚拟V86模式。
在这篇简短的文章中出现的指令和暂存器助忆符号的名称,都在Intel文件中有所指定以及使用在Intel汇编器(Assembler)中(和兼容的,比如微软的MASM、Borland的TASM、CAD-UL的as386等等)。
一个以Intel语法指定的指令"moval,30h"与AT&T语法的"movb$0x30, %al"相当,都是会被转译为两个字节的机器码"B030"(十六进制)。
你可以发现在这段程序中的"mov"或"al",都是原来的Intel助忆符号。
如果我们想要的话,我们可以写一个汇编器由代码'moveimmediatebytehexadecimallyencoded30intolowhalfofthefirstregister'(移动立即值比特十六进制编码30到第一个暂存器的低半部位),来产生相同的机器码。
然而,传统上汇编器(Assembler)一直使用Intel的助忆符号。
运作模式
实模式
在实模式下,存储器的访问是被区段开来。
为了得到最后20比特的存储器地址,要将区段的地址往左移动4位,并且加上偏移的地址。
因此,实模式下总共可以寻址的空间是220字节,或者是1MB,于1979年是相当让人印象深刻的象征。
在实模式下有两种寻址模式:
near和far。
在far模式,区段跟偏移都需要被指定;在near模式,只需要偏移模式被指定,而存储器区段是由适当的区段暂存器获得。
以数据而言是使用DS暂存器,代码是CS暂存器,堆栈是SS暂存器。
举个例子,如果DS是A000h且SI是5677h,DS:
SI会指向记忆体的绝对地址DS×16+SI=A5677h
在这种架构下,两对不同的区段/偏移可以指向一个相同的绝对地址。
因此如果DS是A111h且SI是4567h,DS:
SI会指向跟上一段相同的A5677h。
除了异值同址重复性之外,这种架构无法同时一次拥有4个以上的区段。
此外,CS、DS和SS是为了程序正确功能而必须的,因此仅仅只有ES可以被用来指向其它的地方。
这种模式原本是为了与Intel8085兼容,导致程序员永无止尽的痛苦。
除了以上所说的,8086也拥有16-bit的32K(其变种Intel8088是8-bit的64K)输入输出空间,以及一个由硬件支持的64K(一个区段)存储器堆栈。
只有words(2字节)可以被推入到堆栈中。
堆栈是由存储器的上端往下成长,他的底端是由SS:
SP指向。
有256个中断,可以由硬件或是软件同时组成。
中断是可以串连在一起,使用堆栈来存储返回被中断的程序地址。
16位保护模式
Intel80286可以在不改变任何东西下,支持8086的实模式16位软件,然而它也支持额外的工作模式称为保护模式,可以将可寻址的物理内存扩充到16MB,可寻址的虚拟内存最大到1GB。
这是使用节区暂存器来存储在节区表格中的索引值。
处理器中有两个这样的表格,分别为GDT和LDT,每一个可以存储最多8192个节区的描述子,每一个节区可以给予最大到64KB的存储器访问。
节区表格提供一个24位的基底地址(baseaddress),可以用此基底地址增加想要的偏移量来创造出一个绝对地址。
此外,每一个节区可以被赋予四种权限等级中的一种(称为"rings")。
尽管这个推出的功能是一项进步,但是他们并没有被广泛地使用,因为保护模式的操作系统无法运行当时的实模式软件。
这样的能力只有在随后80386处理器的虚拟86模式中出现。
在同时,操作系统比如OS/2尝试使用类似乒乓的方法,让处理器在保护和实模式间切换。
这样都会让电脑变慢且不安全,像是在实模式下的程序可以轻易地使电脑死机。
OS/2也定义了限制性的程序设计规则允许"FamilyAPI"或"bound"程序可以在实模式或保护模式下运行。
然而这是给原本为保护模式下设计的程序有关,反之则不然。
保护模式程序并不支持节区选择子和物理内存之间的关系。
有时候会错误地相信在16位保护模式下运行实模式的程序,导致IBM必须选择使用Intel保留给BIOS的中断调用。
事实上这类的程序使用任意的选择子数值和使用在上面提到的“节区运算”的方式有关。
这个问题也在Windows3.x上出现。
这个推出版本想要在16位保护模式下运行程序,而先前的版本只能在实模式下运行。
理论上,如果Windows1.x或2.x程序是写得“适当”且避免使用节区运算的方式,它就有可能在真实和保护模式两者下运行。
Windows程序一般来说都会避免节区运算,这是因为Windows实作出软件的虚拟内存方式,及当程序不运行时候,搬移存储器中的代码和数据,所以操作绝对地址的方式是很危险的;当程序不运行时,被认为要保持存储器区块的“handles”,这样的handles已经非常相当于保护模式的选择子。
在保护模式下的Windows3.0运行一个旧的程序,会触发一个警告对话盒,建议在实模式下运行Windows(推测还是仍然可以使用扩充存储器,可能是在80386机器用EMM386模拟,因此它并不被局限于640KB)或是从厂商那更新到新的版本。
好的行为之程序可能可以使用特别的工具来避免这样的对话盒。
不可能有些GUI程序在16位保护模式下运行,且其它GUI程序在实模式运行,可能是因为这会需要两个分开的环境且会依于前面所提到的处理器在两个模式间的乒乓效应。
从Windows3.1版开始,实模式就消失了。
32位保护模式
Intel80386推出后,也许是到目前为止x86架构的最大跃进。
除了需要值得注意的Intel80386SX是32位架构但仅只有24位寻址(和16位数据总线)。
除此之外其他架构都是32位-所有的暂存器、指令集、输出输入空间和存储器寻址。
为了能够在后者所说的功能工作,要使用32位扩充的保护模式。
然而不像286,386所有的区段可以使用32位的偏移量,即使存储器空间有使用区段,但也允许应用程序访问超过4GB空间而不需要区段的分隔。
此外,32位保护模式提供标签页的支持,是一种让虚拟内存得以实现的机制。
没有新的通用暂存器被加入。
所有16位的暂存器除了区段暂存器外都扩充为32位。
Intel在暂存器的助记符号上加入“E”来表示(因此扩充的AX变成EAX,SI变成ESI,依此类推)。
因为有更多的暂存器数量、指令、和运算单元,因此机器码的格式也被扩充。
为了提供与先前的架构兼容,包含运行码的区段可以被标示为16或是32位的指令集。
此外,特殊的前置符号也可以用来在16位的区段包含32位的脚本,反之亦然。
标签页跟区段的存储器访问是为了支持现在多任务操作系统所必须要的。
Linux、386BSD、WindowsNT和Windows95都是一开始为386所发展,因为它是第一颗提供可靠地程序分离存储器空间的支持(每个程序拥有自己的寻址空间)以及可以在必要的情况下打断他们程序的运行(使用ring,一种x86保护模式下权力分级的名称)。
这种386的基本架构变成未来所有x86系列发展的基础。
Intel80386数学辅助运算处理器也在集成到这个CPU之后的x86系列中,也就是Intel80486。
新的FPU可以帮助浮点数运算,对于科学计算和图形设计是非常重要。
系统管理模式
Intel首次在80386SL之后引入其x86体系结构。
虚拟86模式
主条目:
虚拟86模式
功能扩充
MMX和之后
1996年Intel的MMX(AMD认为这是矩阵数学扩充MatrixMathExtensions的缩写,但大多数时候都被当成Multi-MediaExtension,而Intel从来没有官方宣布过词源)技术出现。
尽管这项新的科技得到广泛宣传,但它的精髓是非常简单的:
MMX定义了八个64位SIMD暂存器,与IntelPentium处理器的FPU堆栈有相重叠。
不幸的是,这些指令无法非常简单地对应到由原来C编译器所产生的脚本中。
MMX也只局限于整数的运算。
这项技术的缺点导致MMX在它早期的存在有轻微的影响。
现今,MMX通常是用在某些2D影片应用程序中。
3DNow!
1997年AMD推出3DNow!
,是对于MMX的SIMD的浮点指令增强(针对相同的MMX暂存器)。
尽管这些也没有解决编译器的难题,但这项技术的推出符合了PC上的3D休闲娱乐应用程序之崛起。
3D游戏开发者和3D绘图硬件制造商在AMD的AMDK6和Athlon系列处理器上,使用3DNow!
来帮助增加他们的性能。
微软后来也在其开发的DirectX7.0中加入针对3DNow!
的优化,使当时的Athlon处理器在3D游戏性能上首次全面超过对手英特尔的Pentium3处理器。
SSE
在1999年Intel推出SSE指令集,增加了八个新的128-bit暂存器(不跟其他的暂存器重叠使用)。
这些指令类似于AMD的3DNow!
,主要是增加浮点数运算的SIMD指令。
SSE2
2001年英特尔推出SSE2指令集,增加了:
∙完整地补充了整数指令(与MMX相似)到原来的SSE暂存器。
∙64位的SIMD浮点运算指令到原来的SSE暂存器。
第一个的增加导致MMX几乎是过时可以舍弃的,第二个则允许这些指令可以让传统的编译器现实地产生。
SSE3
于2004年随着Pentium4处理器的改版Prescott核心推出。
SSE3增加特定的存储器和thread-handling指令来提升Intel超线程的性能,在科学计算方面也有增强。
SSE4
2007年1月,Intel公开发表使用其45纳米制程"Penryn"芯片家族的PC和服务器。
"Penryn"是这一系列依据英特尔Core微架构之笔记本电脑、台式机和服务器芯片家族的代号,首次正式发布时共有16款处理器,除了一款IntelCore2ExtremeQX9650是针对普通台式机市场外,其余的双核Xeon5200系列和四核5400系列都是服务器处理器。
基本上Penryn是继Merom之后的缩小版Core2Duo,再加上47条新的SSE4指令集等额外配备。
SSE4指令集之首次发表时间为2006年9月的英特尔开发者论坛(IDF,IntelDeveloperForum)。
另外,x86处理器制造厂商超微也在该公司K10架构的Phenom处理器中,加入4条新的SSE4A指令集。
注意,SSE4与SSE4A无法彼此兼容。
寻址模式
寻址模式在16-bit的x86处理器:
32-bit寻址模式在32-bit或64-bit的x86处理器:
64-bit寻址模式在64-bit的x86处理器:
x86暂存器
16位
自Intel8086和8088起,有14个16比特暂存器。
其中四个(AX,BX,CX,DX)是通用目的(尽管每个暂存器都有附加目的;举个例子:
只有CX可以被用来当作loop(循环)指令的计数器。
)每个暂存器可以被当成两个分开的字节访问(因此BX的高比特可以被当成BH,低比特则可以当成BL)。
除了这些暂存器,还有四个区段暂存器(CS、DS、SS、ES)。
他们用来产生存储器的绝对地址。
还有两个指针暂存器(SP是指向堆栈的底部,BP可以用来指向堆栈或存储器的其它地方)。
两个指针暂存器(SI和DI)可以用来指向数组的内部。
最后,有旗标暂存器(包含状态旗标比如进位、溢出、结果为零,等等)。
以及IP是用来指向目前运行指令的地址。
32位
自Intel80386起,四个通用暂存器(EAX,EBX,ECX,EDX),它们较低的16位分别与原本16位的通用暂存器(AX,BX,CX,DX)重叠共用。
指针暂存器(EIP,EBP,ESP,ESI,EDI)。
区段暂存器除了原本的(CS、DS、SS、ES),另外新增(FS、GS),但是区段暂存器在32位模式下改做为存储器区块的选择子暂存器。
旗标暂存器被扩展为32位,较低的16位与原本在16位下的旗标暂存器重叠共用。
64位
首先是MMX暂存器(MM0~MM7),它们分别与浮点运算器〈FP0~FP7〉相重叠,所以MMX与浮点运算不可同时使用,必须通过切换选择要使用哪一种。
之后在x86正式导入64位架构后,四个通用暂存器(RAX,RBX,RCX,RDX),它们较低的32位分别与原本32位的通用暂存器(EAX,EBX,ECX,EDX)重叠共用。
指针暂存器(RIP,RBP,RSP,RSI,RDI)。
以及增加八个通用暂存器(R8~R15)。
在2002年,由于32位特性的长度,x86的架构开始到达某些设计的极限。
这个导致要处理大量的信息存储大于4GB会有困难,像是在数据库或是影片编辑上可以发现。
英特尔原本已经决定在64位的世代完全地舍弃x86兼容性,推出新的架构称为IA-64技术作为他的Itanium处理器产品线的基础。
IA-64与x86的软件天生不兼容;它使用各种模拟形式来运行x86的软件,不过,以模拟方式来运行的效率十分低下,并且会影响其他程序的运行。
超微主动把32位x86(或称为IA-32)扩充为64位。
它以一个称为AMD64的架构出现(在重命名前也称为x86-64),且以这个技术为基础的第一个产品是单核心的Opteron和Athlon64处理器家族。
由于AMD的64位处理器产品线首先进入市场,且微软也不愿意为英特尔和AMD开发两套不同的64位操作系统,英特尔也被迫采纳AMD64指令集且增加某些新的扩充到他们自己的产品,命名为EM64T架构(显然他们不想承认这些指令集是来自它的主要对手),EM64T后来被英特尔正式更名为Intel64。
这是由非Intel的制造商所发起和设计的第一次重大的x86架构升级。
也许更重要的,它也是第一次Intel实际上从外部来源接受这项本质的技术。
128位
自SSE起,SIMD的暂存器XMM0-XMM15.
256比特
SIMDregistersYMM0-YMM15.
512位
SIMDregistersZMM0-ZMM31.
暂存器结构
通用暂存器(A,B,CandD)
64
56
48
40
32
24
16
8
R?
X
E?
X
?
X
?
H
?
L
在64位模式新增的通用暂存器(R8,R9,R10,R11,R12,R13,R14,R15)
64
56
48
40
32
24
16
8
?
?
D
?
W
?
B
区段暂存器(C,D,S,E,FandG)
16
8
?
S
指针暂存器(SandB)
64
56
48
40
32
24
16
8
R?
P
E?
P
?
P
?
PL
Note:
The ?
PLregistersareonlyavailablein64-bitmode.
索引暂存器(SandD)
64
56
48
40
32
24
16
8
R?
I
E?
I
?
I
?
IL
Note:
The ?
ILregistersareonlyavailablein64-bitmode.
指令指针暂存器(I)
64
56
48
40
32
24
16
8
RIP
EIP
IP
虚拟
虚拟x86是很简单的,因为它的架构已经达到波佩克与戈德堡虚拟化需求。
然而,有好几个商业的虚拟x86产品,比如VMware和微软的VirtualPC。
Intel和AMD两者都有公开宣布未来的x86处理器将会有新的增强来容易达到更有效率的虚拟。
Intel针对这项虚拟特性的代号称为"Vanderpool"和"Silvervale";AMD则使用"Pacifica"这个代号。
x86指令格式
x86与x86-64指令集的指令的格式为:
指令前缀
指令码
ModR/M
SIB
偏移
直接数
InstructionPrefixes
Opcode
Displacement
Immediate
可选。
最多4个单字节前缀。
任何顺序均可。
单字节、双字节、三字节
按需。
0-2位:
R/M
3-5位:
Reg/Opcode
6-7位:
Mod
按需。
0-2位:
Base
3-5位:
Index
6-7位:
Scale
0、1、2、4字节长
0、1、2、4字节长
指令前缀
分为4组,每组用1个字节编码。
每组在指令中至多指定1个前缀值。
4组的顺序可以任意。
∙第1组锁与重复(Lockandrepeat)
o锁(LOCK)编码为:
F0H。
用于互斥访问共享内存的操作。
o非零时重复(REPNE/REPNZ)编码为:
F2H。
用于字符串操作指令。
o为零时重复(REP/REPE/REPZ)编码为:
F3H。
用于字符串操作指令。
∙第2组
o段覆盖(Segmentoverride):
CS、SS、DS、ES、FS、GS的段覆盖前缀的编码分别是2EH、36H、3EH、26H、64H、65H.
o分支提示(Branchhints),用于条件分支指令Jcc。
提示分支不发生编码为2EH;提示分支发生编码为3EH。
∙第3组操作数长度覆盖(Operand-sizeoverride)编码为66H。
用于在16位与32位操作数切换。
∙第4组地址长度覆盖(Address-sizeoverride)编码为67H.用于在16位与32位地址切换。
指令码
长度为1、2或3字节,此外ModR/M中还可能有3位。
对于双字节指令码或三字节指令码,其中的第1个字节为0FH,用于与指令前缀区分。
ModR/M与SIB
许多指令的内存操作数需要使用ModR/M字节作为寻址模式说明符。
其中的mod与r/m组合,共有32个值,表示8个寄存器与24种寻址模式。
reg/opcode表示寄存器号或者额外的3位指令码,其具体含义依赖基本指令码。
Mod与R/M的5位表示的第一操作数(源与目的操作数中寻址方式更复杂的那个操作数,指令码中的“方向位”directionbit(d)给出源或目的操作数哪个是第一操作数)的寻址方式如下:
寻址方式
Mod
R/M
[EAX]
00
000
[ECX]
001
[EDX]
002
[EBX]
003
[--][--]
004
disp32
005
[ESI]
006
[EDI]
007
[EAX]+disp8
01
000
[ECX]+disp8
001
[EDX]+disp8
002
[EBX]+disp8
003
[--][--]+disp8
004
[EBP]+disp8
005
[ESI]+disp8
006
[EDI]+disp8
007
[EAX]+disp32
10
000
[ECX]+disp32
001
[EDX]+disp32
002
[EBX]+disp32
003
[--][--]+disp32
004
[EBP]+disp32
005
[ESI]+disp32
006
[EDI]+disp32
007
EAX/AX/AL/MM0/XMM0
11
000
ECX/CX/CL/MM/XMM1
001
EDX/DX/DL/MM2/XMM2
002
EBX/BX/BL/MM3/XMM3
003
ESP/SP/AH/MM4/XMM4
004
EBP/BP/CH/MM5/XMM5
005
ESI/SI/DH/MM6/XMM6
006
EDI/DI/BH/MM7/XMM7
007
1.[--][--]表示随后的SIB字节指明寻址方