1、i386 的寄存器
80386作为80X86系列中的一员,必须保证向后兼容,也就是说,既要支持16位的处理器,也要支持32位的处理器。在8086中,所有的寄存器都是16位的,下面我们来看一下80386中寄存器有何变化:
· 把16位的通用寄存器、标志寄存器以及指令指针寄存器扩充为32位的寄存器
· 段寄存器仍然为16位。
· 增加4个32位的控制寄存器
· 增加4个系统地址寄存器
· 增加8个调式寄存器
· 增加2个测试寄存器
2、通用寄存器
通用寄存器可用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果。除此之外,它们还各自具有一些特殊功能。汇编语言程序员必须熟悉每个寄存器的一般用途和特殊用途,只有这样,才能在程序中做到正确、合理地使用它们。
16位寄存器组
4个数据寄存器(AX、BX、CX和DX) |
2个变址寄存器(SI和DI) |
2个指针寄存器(SP和BP) |
4个段寄存器(ES、CS、SS和DS) |
1个指令指针寄存器(IP) |
1个标志寄存器(Flags) |
32位寄存器组
32位寄存器组除了包含了先前CPU的所有寄存器,并进行了寄存器位数扩充之外,还增加了2个16位的段寄存器:FS和GS。 |
||
4个数据寄存器(EAX、EBX、ECX和EDX) |
2个变址寄存器(ESI和EDI) |
2个指针寄存器(ESP和EBP) |
6个段寄存器(ES、CS、SS、DS、FS和GS) |
1个指令指针寄存器(EIP) |
1个标志寄存器(EFlags) |
1、数据寄存器
数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。
32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。
4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字节的信息。
寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高; |
|
寄存器BX称为基地址寄存器(Base Register)。它可作为存储器指针来使用; |
|
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数; |
|
寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。 |
在16位CPU中,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,但在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。详细内容请见第3.8节——32位地址的寻址方式。
2、变址寄存器
32位CPU有2个32位通用寄存器ESI和EDI。其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。
寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式(在第3章有详细介绍),为以不同的地址形式访问存储单元提供方便。
变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,而且还具有特殊的功能。
3、指针寄存器
32位CPU有2个32位通用寄存器EBP和ESP。其低16位对应先前CPU中的BP和SP,对低16位数据的存取,不影响高16位的数据。
寄存器EBP、ESP、BP和SP称为指针寄存器(Pointer Register),主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们主要用于访问堆栈内的存储单元,并且规定: |
|
BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据; |
|
SP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。 |
4、段寄存器
段寄存器是根据内存分段的管理模式而设置的。内存单元的物理地址由段寄存器的值和一个偏移量组合而成的,这样可用两个较少位数的值组合成一个可访问较大物理空间的内存地址。
CPU内部的段寄存器: |
|
CS——代码段寄存器(Code Segment Register),其值为代码段的段值; |
|
DS——数据段寄存器(Data Segment Register),其值为数据段的段值; |
|
ES——附加段寄存器(Extra Segment Register),其值为附加数据段的段值; |
|
SS——堆栈段寄存器(Stack Segment Register),其值为堆栈段的段值; |
|
FS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值; |
|
GS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值。 |
在16位CPU系统中,它只有4个段寄存器,所以,程序在任何时刻至多有4个正在使用的段可直接访问;在32位微机系统中,它有6个段寄存器,所以,在此环境下开发的程序最多可同时访问6个段。
32位CPU有两个不同的工作方式:实方式 和 保护方式。在每种方式下,段寄存器的作用是不同的。有关规定简单描述如下:
实方式: |
前4个段寄存器CS、DS、ES和SS与先前CPU中的所对应的段寄存器的含义完全一致,内存单元的逻辑地址仍为“段值:偏移量”的形式。为访问某内存段内的数据,必须使用该段寄存器和存储单元的偏移量。 |
保护方式: |
在此方式下,情况要复杂得多,装入段寄存器的不再是段值,而是称为“选择子”(Selector)的某个值。段寄存器的具体作用在此不作进一步介绍了,有兴趣的读者可参阅其它科技资料。 |
5、指令指针寄存器
32位CPU把指令指针扩展到32位,并记作EIP,EIP的低16位与先前CPU中的IP作用相同。
指令指针EIP、IP(Instruction Pointer)是存放下次将要执行的指令在代码段的偏移量。在具有预取指令功能的系统中,下次要执行的指令通常已被预取到指令队列中,除非发生转移情况。所以,在理解它们的功能时,不考虑存在指令队列的情况。
在实方式下,由于每个段的最大范围为64K,所以,EIP中的高16位肯定都为0,此时,相当于只用其低16位的IP来反映程序中指令的执行次序。
状态和控制寄存器
状态和控制寄存器是由标志寄存器EFLAGS、指令指针EIP和4个控制寄存器组成,如图2.1所示:
|
EFLAGS
EIP
CR0
CR1
CR2
CR3
图2.1状态和控制寄存器
1.指令指针寄存器和标志寄存器
指令指针寄存器EIP中存放下一条将要执行指令的偏移量(offset ),这个偏移量是相对于目前正在运行的代码段寄存器CS而言的。偏移量加上当前代码段的基地址,就形成了下一条指令的地址。EIP中的低16位可以分开来进行访问,给它起名叫指令指针IP寄存器,用于16位寻址。
标志寄存器EFLAGS存放有关处理器的控制标志,如图2.2所示。标志寄存器中的第1、3、5、15位及18~31位都没有定义。
图2.2 i386标志寄存器EFLAGS
在这些标志位中,我们只介绍在Linux内核代码中常用且重要的几个标志位:
第8位TF(Trap Flag)是自陷标志,当将其置1时则可以进行单步执行。当指令执行完后,就可能产生异常1的自陷(参看第四章)。也就是说,在程序的执行过程中,每执行完一条指令,都要由异常1处理程序 (在Linux内核中叫做debug())进行检验。当将第8位清0后,且将断点地址装入调试寄存器DR0~DR3时,才会产生异常1的自陷。
第12、13位IOPL是输入输出特权级位,这是保护模式下要使用的两个标志位。由于输入输出特权级标志共两位,它的取值范围只可能是0、1、2和3共4个值,恰好与输入输出特权级0~3级相对应。但Linux内核只使用了两个级别,即0和3级,0表示内核级,3表示用户级。在当前任务的特权级CPL(Current Privilege Level)高于或等于输入输出特权级时,就可以执行像IN、OUT、INS、OUTS、STI、CLI和LOCK等指令而不会产生异常13(即保护异常)。在当前任务特权级CPL为0时,POPF(从栈中弹出至标志位)指令和中断返回指令IRET可以改变IOPL字段的值。
第9位IF(Interrupt Flag)是中断标志位,是用来表示允许或者禁止外部中断(参看第四章)。若第9位IF被置为1,则允许CPU接收外部中断请求信号;若将IF位清0,则表示禁止外部中断。在保护模式下,只有当第12、13位指出当前CPL为最高特权级时,才允许将新值置入标志寄存器EFLAGS以改变IF位的值。
第10位DF(Direction Flag)是定向标志。DF位规定了在执行串操作的过程中,对源变址寄存器ESI或目标变址寄存器EDI是增值还是减值。如果DF为1,则寄存器减值;若DF为0,则寄存器值增加。
第14位NT是嵌套任务标志位。在保护模式下常使用这个标志。当80386在发生中断和执行CALL指令时就有可能引起任务切换。若是由于中断或由于执行CALL指令而出现了任务切换,则将NT置为1。若没有任务切换,则将NT位清0。
第17位VM (Virtual 8086 Mode Flag)是虚拟8086方式标志,是80386新设置的一个标志位。表示80386CPU是在虚拟8086环境中运行。如果80386CPU是在保护模式下运行,而VM为又被置成1,这时80386就转换成虚拟8086操作方式,使全部段操作就像是在8086CPU上运行一样。VM位只能由两种方式中的一种方式给予设置,即或者是在保护模式下,由最高特权级(0)级代码段的中断返回指令IRET设置,或者是由任务转换进行设置。Linux内核实现了虚拟8086方式,但在本书中我们不准备对此进行详细讨论。
从上面的介绍可以看出,要正确理解标志寄存器EFLAGS的各个标志需要很多相关的知识,有些内容在本章的后续部分还会涉及到。在后面的章节中,你会体会如何灵活应用这些标志。
2.控制寄存器
状态和控制寄存器组除了EFLAGS、EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3。现在我们详细看看它们的结构,如图 2-3所示。
图 2-3 386中的控制寄存器组
这几个寄存器中保存全局性和任务无关的机器状态。
CR0中包含了6个预定义标志,0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。1位是监控协处理位MP(Moniter coprocessor),它与第3位一起决定:当TS=1时操作码WAIT是否产生一个“协处理器不能使用”的出错信号。第3位是任务转换位(Task Switch),当一个任务转换完成之后,自动将它置1。随着TS=1,就不能使用协处理器。CR0的第2位是模拟协处理器位 EM (Emulate coprocessor),如果EM=1,则不能使用协处理器,如果EM=0,则允许使用协处理器。第4位是微处理器的扩展类型位ET(Processor Extension Type),其内保存着处理器扩展类型的信息,如果ET=0,则标识系统使用的是287协处理器,如果 ET=1,则表示系统使用的是387浮点协处理器。CR0的第31位是分页允许位(Paging Enable),它表示芯片上的分页部件是否允许工作,下一节就会讲到。由PG位和PE位定义的操作方式如图2.4 所示。
图 2-4 PG位和PE位定义的操作方式
CR1是未定义的控制寄存器,供将来的处理器使用。
CR2是页故障线性地址寄存器,保存最后一次出现页故障的全32位线性地址。
CR3是页目录基址寄存器,保存页目录表的物理地址,页目录表总是放在以4K字节为单位的存储器边界上,因此,它的地址的低12位总为0,不起作用,即使写上内容,也不会被理会。
这几个寄存器是与分页机制密切相关的,因此,在进程管理及虚拟内存管理中会涉及到这几个寄存器,读者要记住CR0、CR2及CR3这三个寄存器的内容。
3、16位、32位和64位操作系统的区别
我们这里先讲32bit与64bit系统的区别: 大体上来讲,64位的系统比32位的系统计算处理能力更精确更加强.-----------用计算器计算时有64位数字可以显示出来,而我们普通的32位系统最精确只能显示32个数字,这是一个小的区别.---------最主要的区别就是64位的XP需要你的CPU也是64位的.64位的技术比32位先进,但由于配套的相关的软硬件技术尚未成熟,很多情况下64位系统只能运行32位软件,现在的64位系统就象是一部跑车由于没有公路只能在农田里跑一样. --32位、64位代表的是使用cpu位数(64,32) --------------------------------------------- 16、32、64位是指cpu可寻址的长度。例如32位计算机,CPU可寻址的范围是0到2的32次方减1,也就是说内存最大可达2的32次方个字节,也就是4GB. 机器使用位数来表示是说每个机器在一个cpu时间里面并行处理2进制位的位数。32位的计算机是说我们的cpu在一个时间段里面能并行处理32位2进制数,操作系统也是一样的。 ------所谓16位、32位、64位等术语有时指总线宽度,有时指指令宽度(在定长指令集中), 而在操作系统理论中主要是指内存寻址的宽度。如果内存的寻址宽度是16位,那么每一个内存地址可以用16个二进制位来表示,也就是说可以在64KB的范围内寻址。 同样道理32位的宽度对应4GB的寻址范围,64位的宽度对应16 Exabyte的寻址范围。内存寻址范围并非仅仅是对操作系统而言的,其他类型的软件的设计有时也会被寻址范围而影响。但是在操作系统的设计与实现中,寻址范围却有着更为重要的意义。 --专家对此解答说:“当计算机面临大量的数据流时,32位的寄存器和指令集不能及时进行相应的处理运算。32位处理器一次只能处理32位,也就是4个字节的数据;而64位处理器一次就能处理64位,即8个字节的数据。形象地说,32位好像是一个狭窄的单车道,当车流过多的时候,就无法承载这些负荷,而64位好比一个宽阔的高速公路,所以在多任务,多程序处理的情况下,应用64位计算平台才能随心所欲的加速、把电脑的应用性能发挥到最好。” |
4 系统地址寄存器
80386有4个系统地址寄存器,如图2.5所示,它保存操作系统要保护的信息和地址转换表信息:
47 32位基地址 16 15 界限 0
|
|
|
|
GDTR
IDTR
TR
|
|
LDTR
图2.5 80386系统地址寄存器
这4个专用寄存器用于引用在保护模式下所需要的表和段,它们的名称和作用如下:
· 全局描述符表寄存器GDTR(Global Descriptor Table Register ),是48位寄存器,用来保存全局描述符表(GDT)的32位基地址和16为GDT的界限。
· 中断描述符表寄存器IDTR(Interrupt Descriptor Table Register),是48位寄存器,用来保存中断描述符表(IDT)的32位基地址和16为IDT的界限。
· 局部描述符表寄存器LDTR(Global Descriptor Table Register ),是16位寄存器,保存局部描述符表LDT段的选择符。
· 任务状态寄存器TR(Task State Register)是16位寄存器,用于保存任务状态段TSS段的16位选择符。
用以上4个寄存器给目前正在执行的任务(或进程)定义任务环境、地址空间和中断向量空间。有关全局描述符表GST、中断描述符表IDT、局部描述符表LDT及任务状态段TSS的具体内容将在稍后进行详细描述。