CPU寄存器(转载+整理)

今天我来学eip寄存器。。它可存着我cpu取指令的地址,没有了它,cpu就无法取下面的指令(通俗点cpu就无法行。每次相应汇编指令行完相eip就会增加。

 

80386 cpu址范是4GB。所以它的址模式是平坦模式的。里我描述下cpu过读取eip寄存器行的大致程。。

 

     一个程序开始行了。首先PEloader的pe文件,取我pe文件的基地址和入口RVA地址(相于基地址的偏移),并且取相应节构的,然后将我的程序映射到内存。

 

    ,映射到内存以后.. PE loader把返回的程序入口点cpu的eip寄存器赋值,然后通知我的cpu:“ 并且:我映射完了,你可以行了。eip也相赋值了。此cpu知道了eip,那么它通将eip值传送到路,并送入相的地址总线上。那么此cpu就通eip取eip偏移上的二制数据(我里用汇编指令来表示)并送到数据总线上,最后送到指令冲区。送到指令冲区后,那么此eip会自的增加其入指令的数量,以便往下行, 最后行控制器第七指令冲区的指令并且往下行。

 

cpu每次行控制器取完,相的就在通eip寄存器去行下一次的取指令工作。。每次cpu取指令到指令冲区,相的eip寄存器的增加,增加大小的就是取指令的字大小(也可以度)。。

 

个例子我程序的入口点是

 push ebp汇编指令。                                                                       (注:此eip+ 取指令的大小)

   首先cpu - >取eip - > 来到eip的偏移 - >取push ebp-> 存放指令到指令冲区    - >行.. 反复循

 

 

在大家知道eip的作用性了吧。每次cpu行都要先取eip寄存器的,然后定位eip指向的内存地址,并且汇编指令,最后行。

 

要介一个jmp指令,大家都比熟悉吧。。 但是你是否知道每次行jmp 后,eip的化呢。其你猜也可以猜到。jmp名思指令。行后eip=后面要跳的地址。

 

个例子:

       之前eip =00403021h ,行jmp 00403058h 行完指令后eip = 00403058H

 

小作:

    1.目前的eip寄存器的是eip =00400001h , 00400001h偏移汇编指令是movebp,esp,个指令占2个字。那么行完句指令后,此的eip是多少?

    2.行以下几句指令后,eip生了几次化?

pushebp

addax,ax

movebp

    3.行以下句后,eip生了几次化?最后的eip等于多少

pushebp 

movebp, esp

jmp   00405060hs

 

 

首先介常看到的一些寄存:
4个数据寄存器(EAXEBXECXEDX)
2
个变址和指针寄存器(ESIEDI)
2个指针寄存器(ESPEBP)


4个数据寄存器(EAXEBXECXEDX)
32CPU432位的通用寄存器EAXEBXECXEDX。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AXBXCXDX,它和先前的CPU中的寄存器相一致。
416位寄存器又可分割成8个独立的8位寄存器(AXAH-ALBXBH-BLCXCH-CLDXDH-DL),每个寄存器都有自己的名称,可独立存取。程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字节的信息。

那么如何理解eax,ax,al(ah)之间的关系呢?
专业点可以这样解释:Eax32位寄存器,ax16位寄存器,al(ah)是八位寄存器。
那么eax存储的数据就是ax的两倍,axal(ah)的两倍。
Eax可以存储的数字是DWORD(双字)ax存储的是WORD(字)AL(AH)存储的是BYTE(字节),那么为什么又有AHAL呢,我们可以这样理解,AX=AH+ALAH存储的是AX的高8位数据,AL存储的是AX的低八位数据。H这里就是HIGH,L就是LOW.
假设eax是红色区域,那么eax现在就是64636261
那么ax就是eax的低十六位,也就是6261
Al61AH62



其他ebx,ecx,edx也有类似的bx,bl,bh等对应的寄存器,原理和上面相同。

在用途方面,他们有各自默认的用途:
Eax用来保存所有API函数的返回值。
寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;
寄存器BX称为基地址寄存器(Base Register)。它可作为存储器指针来使用;
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。

由于存储的数据大小关系,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。(什么是基址,什么是变址以后会说到)

2个变址和指针寄存器(ESI和EDI)
32位CPU有2个32位通用寄存器ESI和EDI。其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。

寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,而且还具有特殊的功能。

2个重要的指针寄存器(ESP和EBP)


这两个指针寄存器都和“栈”这个神秘的东东有关,那么什么是栈呢?这俩指针寄存器又有何作用呢?


从计算机科学的角度看,栈是一种数据结构,是一种先进后出的数据表。栈的最常见操作有两种:Push(入栈)和Pop(出栈)。


我们可以把栈想象成一摞扑克牌:
PUSH:为栈增加一个元素的操作是push,相当于在这摞扑克牌最上面再放一张

POP:从栈中取出一个元素的操作叫做POP,相当于从这摞扑克牌取出最上面的一

张。

TOP:标识栈顶位置,并且是动态变化的。每做一次PUSH操作,它都会自增1;

相反,每做一次POP操作,它会自减1。栈顶元素相当于扑克牌最上面一张,只有


这张牌的花色是当前可以看到的。

BASE:标识栈底位置,它记录着扑克牌最下面一张的位置。BASE用于防止栈空后

继续弹栈(牌发完时就不能再去揭牌了)。很明显,一般情况下,BASE是不会变动


的。

用王爽《汇编语言》中的图说明一下push和pop操作
代码如下:
mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
pop ax
pop bx
pop cx

mov是传送数据的指令,mov ax,0123H表明把0123H这个值给ax
H代表0123是十六进制数



mov是传送数据的指令,mov ax,0123H表明把0123H这个值给ax
H代表0123是十六进制数
图中左边的10000H等数值表明内存地址
箭头指向栈顶位置

那么针对此例栈底就是1000FH
栈顶由于入栈和出栈操作在不断变化。

那么在这里栈底1000FH就是BP 栈顶(不断变化的箭头)就是SP
(BP和SP分别是16位下的寄存器,与ebp,esp类似)

内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函

数的调用。对于类似C语言这样的高级语言,我们无需担心他们是如何操作的。一般说来,只有在使用汇编语言的时候,才需要和它直接打交道。

那么ESP和EBP指的分别是什么呢?

(1)ESP:栈指针寄存器(extended stackpointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

 

X86 CPU的EFLAGS寄存器各个标识位

TF(Trap Flag)——位8,跟踪标志。置1 则开启单步执行调试模式,置0 则关闭。在单步执行模式下,处理器在每条指令后产生一个调试异常,这样在每条指令执行后都可以查看执行程序的状态。如果程序用POPF、POPFD或者ET指令设置TF标志,那么这之后的第一条指令就会产生调试异常。

 

IF (Interrupt enable)——位9,中断许可标志。控制处理器对可屏蔽硬件中断请求的响应。置1 则开启可屏蔽硬件中断响应,置0 则关闭可屏蔽硬件中断响应。IF标志不影响异常和不可屏蔽中断(NMI)的产生。CPL、IOPL和控制寄存器CR4中的VME标志决定着IF 标志是否可由CLI、STI、POPF、POPFD和IRET指令修改。

 

IOPL(I/O Privilege Level Field)——位12&位13,I/O 特权域。标示当前进程或任务的I/O特权级别。当前进程或任务的CPL必须小于或等于IOPL才可以访问I/O 地址空间。只有CPL为0 的进程才可用POPF和IRET指令修改这个域。IOPL是控制IF标志修改的机制之一,同时也是当虚拟模式扩展生效时(控制寄存器CR4中的VME置位),控制虚拟8086 模式下中断处理的机制之一。

 

NT (Nested Task)——位14,嵌套任务。控制被中断和被调用的任务的嵌套执行链。处理器调用一个由CALL指令、中断或者异常触发的任务时设置该位,调用IRET指令返回时检测并修改该位。该标志可以由POPF/POPFD指令直接置位或置0,然而在应用程序中修改该标志的状态会产生不可预料的异常。

 

RF(Resume)——位16, 恢复。控制处理器对指令断点的响应。置1 则暂时禁用指令断点产生调试异常(debugexceptions,#DE),但是其它异常情况仍可以产生异常。置0 则指令断点产生调试异常。RF标志的主要功能是许可从调试异常(指令断点引发的)后面的那个指令开始继续执行。调试软件必须在用IRETD指令返回到被中断程序之前,将栈中的EFLAGES映象中的该位置为1,以阻止指令断点产生另外的调试异常。在返回并成功执行断点指令之后,处理器会自动清零该位,从而许可继续产生指令断点故障。

 

VM (Virtual-8086 mode)——位17,虚拟8086 模式。置1 则进入虚拟8086 模式,置0 则返回保护模式。

 

AC (Alignment check)——位18,对齐检查。置位该标志和控制寄存器CR0的AM标志则启用对内存引用的对齐检查,清除这两个标志则禁用对齐检查。当引用一个没有对齐的操作数时,将会产生一个对齐检查异常,比如在奇地址引用一个字地址或在不是4 的倍数的地址引用一个双字地址。对齐检查异常只在用户态(3 级特权)下产生。默认特权为0 的内存引用,比如段描述符表的装载,并不产生这个异常,尽管同样的操作在用户态会产生异常。对齐检查异常用于检查数据的对齐,当处理器之间交换数据时这很有用,交换数据需要所有的数据对齐。对齐检查异常也可供解释程序使用。让某些指针不对齐就好比做上特殊标记,这样就无需对每个指针都进行检查,只在用到的时候,对这些特殊指针进行处理就可以了。

 

VIF (Virtual Interrupt)——位19,虚拟中断。是IF标志的一个虚拟映象。这个标志是和VIP标志一起使用的。当控制寄存器CR4中的VME或者PVI标志置为1 且IOPL小于3 时,处理器只识别VIF 标志(VME标志用来启用虚拟8086 模式扩展,PVI标志启用保护模式下的虚拟中断)。

 

VIP (Virtual interrupt pending)——位20,虚拟中断等待。置1 表明有一个正在等待处理的中断,置0 表明没有等待处理的中断。该标志和VIF一起使用。处理器读取该标志但从来不修改它。当VME标志或者控制寄存器CR4 中的PVI标志置1 且IOPL小于3 时,处理器只识别VIP 标志。(VME标志启用虚拟8086模式扩展,PVI标志启用保护模式虚拟中断)。

 

ID (Identification)——识别(第21位)。置1 或0 表明是否支持CPUID指令。

 

其它的通用标志:

CF——进位标志

PF——恢复标志

AF——辅助标志

ZF——零标志

SF——负号标志

DF——方向标志

OF——溢出标志

 

鉴于EFLAGS寄存器的重要性,所以将这一部分内容从理器体系构及址模式一文中单独抽出另成一文,这部分内容主要来自Intel Developer Mannual,在后续的内核系列中遇到的许多和EFLAGS寄存器有关的内容将直接从本文引用。众所周知,IA-32体系结构为通用系统(general system)提供了16个基本的程序执行寄存器:包含一些通用目的寄存器(General-purpose registers)、段寄存器(Segment registers)以及EFLAGS和EIP寄存器,而后两者对于程序的执行来说可谓至关重要。

其中EIP寄存器主要用于存放当前代码段即将被执行的下一条指令的偏移,但其本质上并不能直接被指令直接访问。【it is controlled implicitly by control-transferinstructions (such as JMP, Jcc, CALL, and RET), interrupts, and exceptions.】很显然,这个寄存器指令由控制转移指令、中断及异常所控制。【The only way to read the EIP register is toexecute a CALL instruction and then read the value of the return instructionpointer from the procedure stack.The EIP register can be loaded indirectly bymodifying the value of a return instruction pointer on the procedure stack andexecuting a return instruction (RET or IRET)】  这里也已经说的很清楚了,读操作通过执行call指令并取得栈中所存放的地址来实现,而写操作则通过修改程序栈中的返回指令指针并执行RET/IRET指令来完成,因此尽管这个寄存器相当重要,但其实并不是操作系统在实现过程中所需关注的焦点。

相对来讲,EFLAGS寄存器对于操作系统则重要得多。EFLAGS(programstatus and control) register主要用于提供程序的状态及进行相应的控制,【The EFLGAS register report onthe status of the program being executed and allows limited(application-programlevel) control of the process.】在64-bit模式下,EFLGAS寄存器被扩展为64位的RFLGAS寄存器,高32位被保留,而低32位则与EFLAGS寄存器相同。

32位的EFLAGS寄存器包含一组状态标志、系统标志以及一个控制标志。在x86处理器初始化之后,EFLAGS寄存器的状态值为0000 0002H。第1、3、5、15以及22到31位均被保留,这个寄存器中的有些标志通过使用特殊的通用指令可以直接被修改,但并没有指令能够检查或者修改整个寄存器。通过使用LAHF/SAHF/PUSHF/POPF/POPFD等指令,可以将EFLAGS寄存器的标志位成组移到程序栈或EAX寄存器,或者从这些设施中将操作后的结果保存到EFLAGS寄存器中。在EFLAGS寄存器的内容被传送到栈或是EAX寄存器后,可以通过位操作指令(BT, BTS, BTR, BTC)检查或修改这些标志位。当调用中断或异常处理程序时,处理器将在程序栈上自动保存EFLAGS的状态值。若在中断或异常处理时发生任务切换,那么EFLAGS寄存器的状态将被保存在TSS中【thestate of the EFLAGS register is saved in the TSS for the task being suspended.】,注意是将要被挂起的本次任务的状态


EFLAGS Register

 

1、状态标志(Status Flags)
EFLAGS寄存器的状态标志(0、2、4、6、7以及11位)指示算术指令(如ADD, SUB, MUL以及DIV指令)的结果,这些状态标志的作用如下:

CF(bit 0) [Carry flag]   若算术操作产生的结果在最高有效位(most-significant bit)发生进位或借位则将其置1,反之清零。这个标志指示无符号整型运算的溢出状态,这个标志同样在多倍精度运算(multiple-precision arithmetic)中使用。
PF(bit 2) [Parityflag]   如果结果的最低有效字节(least-significant byte)包含偶数个1位则该位置1,否则清零。
AF(bit 4) [Adjustflag]   如果算术操作在结果的第3位发生进位或借位则将该标志置1,否则清零。这个标志在BCD(binary-codedecimal)算术运算中被使用。
ZF(bit 6) [Zeroflag]   若结果为0则将其置1,反之清零。
SF(bit 7) [Signflag]   该标志被设置为有符号整型的最高有效位。(0指示结果为正,反之则为负)
OF(bit 11) [Overflowflag]   如果整型结果是较大的正数或较小的负数,并且无法匹配目的操作数时将该位置1,反之清零。这个标志为带符号整型运算指示溢出状态。

在这些状态标志中,只有CF标志能够通过使用STC, CLC以及CMC指令被直接修改,或者通过位指令(BT, BTS, BTR以及BTC)将指定的位拷贝至CF标志中。

这些状态标志允许单个的算术操作产生三种不同数据类型的结果:无符号整型,有符号整型以及BCD整型。如果把该结果当做无符号整型,那么CF标志指示越界(out-of-range)状态——即进位或借位,如果被当做有符号整型,则OF标志指示进位或借位,若作为BCD数,那么AF标志指示进位或借位。SF标志指示有符号整数的符号位,ZF指示结果为零。此外在执行多倍精度算术运算时,CF标志用来将一次运算过程中带进位的加法(ADC)或带借位的减法(SBB)产生的进位或借位传递到下一次运算过程中。

2、DF标志(DF flag)
这个方向标志(位于EFLAGS寄存器的第10位)控制串指令(MOVS, CMPS, SCAS, LODS以及STOS)。设置DF标志使得串指令自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。STD以及CLD指令分别用于设置以及清除DF标志。

3、系统标志以及IOPL域(System Flags andIOPL Field)
EFLAGS寄存器中的这部分标志用于控制操作系统或是执行操作,它们不允许被应用程序所修改。这些标志的作用如下:

TF(bit 8) [Trap flag]   将该位设置为1以允许单步调试模式,清零则禁用该模式。
IF(bit 9) [Interruptenable flag]   该标志用于控制处理器对可屏蔽中断请求(maskable interrupt requests)的响应。置1以响应可屏蔽中断,反之则禁止可屏蔽中断。
IOPL(bits 12 and 13)[I/O privilege level field]   指示当前运行任务的I/O特权级(I/O privilege level),正在运行任务的当前特权级(CPL)必须小于或等于I/O特权级才能允许访问I/O地址空间。这个域只能在CPL为0时才能通过POPF以及IRET指令修改。
NT(bit 14) [Nestedtask flag]   这个标志控制中断链和被调用任务。若当前任务与前一个执行任务相关则置1,反之则清零。
RF(bit 16) [Resumeflag]   控制处理器对调试异常的响应。
VM(bit 17)[Virtual-8086 mode flag]   置1以允许虚拟8086模式,清除则返回保护模式。
AC(bit 18)[Alignment check flag]   该标志以及在CR0寄存器中的AM位置1时将允许内存引用的对齐检查,以上两个标志中至少有一个被清零则禁用对齐检查。
VIF(bit 19) [Virtual interrupt flag]   该标志是IF标志的虚拟镜像(Virtual image),与VIP标志结合起来使用。使用这个标志以及VIP标志,并设置CR4控制寄存器中的VME标志就可以允许虚拟模式扩展(virtual mode extensions)
VIP(bit 20) [Virtualinterrupt pending flag]   该位置1以指示一个中断正在被挂起,当没有中断挂起时该位清零。【Software sets and clears this flag; theprocessor only reads it.】与VIF标志结合使用。
ID(bit 21)[Identification flag]   程序能够设置或清除这个标志指示了处理器对CPUID指令的支持。

【For a detailed description of these flags:see Chapter 3, "Protected-Mode Memory Management"】

 

你可能感兴趣的:(C/C++)