开始读Linux内核相关书籍时,在书店里碰到一个计算机专业科班出身的朋友,向他请教时,他认为学习Linux内核不需要汇编和计算机体系结构等相关的知识。可是结合到现在的学习经历,我却越来越觉得为了搞清楚Linux内核相关设计和运行原理,自己那点自学来的汇编知识不但不够,还大大的需要补充。本文是我今日对微处理器寄存器学习总结所得,主要是翻译自《Intel 微处理器英文第7版》,阅读的过程中我参考了网上可以下载到的该书第六版的中文版和一篇关于寄存器在Visual Stdio 编译器中惯用方法的文章《汇编-32位寄存器的功能及其使用之整理篇》一文,但是考虑之后没有将其大段引用。

编程模型


按位分类

8086的编程模型包括81632位的寄存器。

八位的寄存器包括AHAL,BH,BL,CH,CL,DHDL

16位寄存器包括AX,BX,CX,DX,SP,BP,DI,SI,IP,FLAGS,CS,DS,ES,SS,FS,GS

扩展的32位的指令包括EAX,EBX,ECX,EDX,ESP,EBP,EDI,ESI,EIPEFLAGS

所有的32位寄存器和16位寄存器中的FS或者GS都仅仅能够在80386以上使用。

按照用途分类

一些寄存器是通用寄存器或者多用途寄存器,而另外的一些则是特殊用途的寄存器。多用途寄存器包括EAXEBXECXEDXEBPEDIESI。这些寄存器都是可变大小的,并且能够被应用程序用于几乎所有的目的。

也有人按照用途将这些寄存器分为以下四类:

 4个数据寄存器(EAXEBXECXEDX)

 2个变址和指针寄存器(ESIEDI), 2个指针寄存器(ESPEBP)

 6个段寄存器(CSDSESSSFSGS)

 1个指令指针寄存器(EIP) ,1个标志寄存器(EFlags)

寄存器的易失性

一些寄存器在函数中常常是变化的,而另外一些却是不变的。这是编译器所决定的。因为寄存器是不会自动保存的(虽然有些汇编语言会自动保存,但是x86 是不会的),所以编码时要自己保存。这句话的意思是:当一个函数被调用,是不保证在函数返回时,易失寄存器上的值不变的;但是函数必须负责保存非易失寄存器中的值。

微软编译器的寄存器使用习惯如下:

1) 易失寄存器: ecx, edx

2) 非易失寄存器 : ebx, esi, edi, ebp

3) 其他特殊寄存器 : eax, esp (discussed later)

多用途寄存器

EAX(累加器) EAX可以被引用成32位(EAX),16位(AX)和8位(AHHL)。注意如果8位或者16位寄存器被寻址,则仅仅会改变32位寄存器的一部分而不会影响到其他部分。累加器可以被用来做加减乘除这样的指令,也可以被用作一些调整指令。对于这些调整指令,累加器具备一个特殊目的,但是它仍然通常被认为是多用途寄存器。在80386之上的微处理器(注意不是所有版本)中,EAX寄存器也可以持有内存系统地址的偏移地址。

EBX (基址)     EBX可以被作为EBXBXBHBL被寻址,在所有版本的微处理器(包括16位)中,BX寄存器有时会持有内存系统位置的偏移地址。80386以上,EBX也可以用来寻址内存数据。

ECX(计数)  ECX是一个通用目的计数器,它持有多种指令的计数。自80386以上,ECX计数器也可以持有内存数据的偏移地址(注意此处不是所有版本)。那些使用了计数器的指令包括:重复字符串指令(REP/REPE/REPNE)、shift、rotate 和 LOOP/LOOPD 指令Shift 指令和 rotate 指令使用CL作为计数器。重复字符串指令使用CX,而LOOP/LOOPD指令使用CX或者ECX指令。

EDX(数据)     EDX是一个通用目的数据寄存器,它持有乘法运算结果的一部分或者除法运算之前的被除数。自80386以上该寄存器也被用作寻址内存数据。

EBP(基址指针)  在所有版本的微处理器中,EBP指向内存位置,并且用作内存数据传输。该寄存器可以被作为BP或者EBP寻址。

EDI(目标索引) EDI通常寻址一些字符串指令的字符串目标数据。它也可以起到32或者16位通用寄存器的作用。

ESI(源索引) ESI被用作ESI或者SI,源索引寄存器通常寻址字符串指令的源字符串数据。像EDI一样,ESI也可以起到通用寄存器的作用。

特殊目的寄存器

特殊目的寄存器包括EIPESPEFLAGS和段寄存器CS、DS、ES、SS、FS、GS

EIP(指令指针) EIP寻址作为代码段定义的内存段中的下一个指令。该寄存器是实模式下的IP指令和80386以上的保护模式中的EIP指令。注意:8086、808880286不包含EIP寄存器,仅仅80286以上的寄存器有保护模式。指令指针指向程序的下一条指令,被微处理器用来寻找代码段中下一个序列指令。指令指针可以被通过jump或者call指令修改。

ESP(堆栈指针) ESP寻址被称为堆栈的内存区域。堆栈内存以指针的形式存储数据并且在下文寻址堆栈数据的指令里得到解释。该寄存器用在16位是SP,用在32位是ESP

EFLAGS(标志)  EFLAGS指示微处理器的条件并且控制它的操作。下图显示了微处理器所有版本的注册器标志。注意这些标志都是后向兼容的。 8086-80286拥有一个FLAG寄存器,80386以上包括一个EFLAG寄存器(将标志扩展到32位)。


最右边的信号的五个位和溢出标志会在大多数算数和逻辑指令执行之后会被改变。这些所有的标志对于数据传递和程序控制都是不被改变的。一些标志也被用来在微处理器中控制特征。

一、运算结果标志位(6个)

C(进位标志,Carry Flag) 进位标志保存加法的进位或减法的借位,也可以用进位标志指示由某些程序或进程引发的错误条件,这在DOS功能调用尤其有用。

  P(奇偶性标志,Parity Flag)  奇偶标志表示结果数中1的个数是奇数还是偶数,是奇数则该标志是逻辑0,是偶数则该标志是逻辑1。如果某个二进制数含有31的位,它的奇偶性为奇数。如果某个二进制数包含0个为l位,则它的奇偶性为偶数。利用PF可进行奇偶校验检查,或产生奇偶校验位。奇偶性标志在现代程序设计中很少使用它是早期Intel微处理器在数据通信环境中校验数据的一种手段。今天,奇偶校验常常由数据通信设备完成,而不是由微处理器完成。

  A(辅助进位标志,Auxiliary Carry Flag)  在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:
(1)、在字操作时,发生低字节向高字节进位或借位时;
(2)、在字节操作时,发生低4位向高4位进位或借位时。

DDABAS指令测试这个特殊标志位,以便在BCD加法或减法后对AL中的值进行十进制调整。除此以外,微处理器或者任何其他指令都不使用A标志位。

Z(零,Zero Flag) 零标志表示一个算术或逻辑操作的结果是否为0。如果Z=1,表示结果为0;如果Z=0,表示结果不为0

S(符号,Sign Flag 符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。

O (溢出,Overflow Flag  溢出标志在有符号数进行加或减时可能出现。溢出指示运算结果已超出机器能够表示的范围。对于无符号的操作,不考虑溢出标志。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。”溢出”和”进位”是两个不同含义的概念,不要混淆。如果不太清楚的话,请查阅《计算机组成原理》课程中的有关章节。

对以上6个运算结果标志位,在一般编程情况下,标志位CF、ZF、SF和OF的使用频率较高,而标志位PF和AF的使用频率较低。

二、状态控制标志位

T(追踪标志,Trap Flag  追踪标志能够激活微处理器芯片上的调试功能对程序进行调试,以便找到错误或故障。如果T标志为允许1),则微处理器根据调试寄存器和控制寄存器的指示中断程序流(CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求)。如果T标志为0,则禁止捕捉调试性能。VC 程序可以利用追踪特性和调试寄存器调试有缺陷的软件。

I (中断,Interrupt-enable Flag) 中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:
(1)、当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;
(2)、当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。
CPU的指令系统中也有专门的指令来改变标志位IF的值。

I标志的状态SLI(置位I标志)CLI(清除I标志)指令控制。

D(方向Direction Flag)  在串指令操作期间,方向标志为DISI寄存器选择递增方式或递减方式。如果D=1,则寄存器内容自动地递减如果D=0,则寄存器内容自动地递增。D标志用STD (置位方向)指令置位,用CLD(清除方向指令清除。

三、32位标志寄存器增加的标志位

IOPL(I/O优先级)  输人/输出优先级标志用于保护模式操作时为设备选择优先级。如果当前任务的优先级高于工IOPL,则到I/O指令能顺利执行;如果IOPL比当前任务的优先级低。则产生中断,导致执行程序被挂起。注意,00级是最高优先级,11级是最低优先级。

NT(任务嵌套,Nested Task   任务嵌套标志指示在保护模式下当前执行的任务嵌套于另一任务中。当任务被软件嵌套时,这个标志置位。嵌套任务标志NT用来控制中断返回指令IRET的执行。具体规定如下:
(1)、当NT=0,用堆栈中保存的值恢复EFLAGS、CS和EIP,执行常规的中断返回操作;
(2)、当NT=1,通过任务转换实现中断返回。

RF(恢复,Restart Flag  恢复标志和调试寄存器一起使用,控制在下条指令后恢复程序的执行,用来控制是否接受调试故障规定:RF=0时,表示”接受”调试故障,否则拒绝之。在成功执行完一条指令后,处理机把RF置为0,当接受到一个非调试故障时,处理机就把它置为1。

VM(虚拟方式,Virtual 8086 Mode) 虚拟方式标志用于在保护模式系统中选择虚拟操作模式。虚拟模式系统允许多个1 MH长的DOS存储器分区共存于存储器系统中。这样可以允许系统执行多个DOS程序。

如果该标志的值为1,则表示处理机处于虚拟的8086方式下的工作状态,否则,处理机处于一般保护方式下的工作状态。

AC(对齐检查) 当寻址一个字或双字时,如果地址不是在字或双字的边界上,对齐检查标志被激活为1。只有8048bSX微处理器包含对齐检查,这个位用来与其配套的协处理器80487SX同步。

VIF(虚拟中断)  虚拟中断标志是中断标志位的副本,只有Pentium-.Fentiurn 4微处理器才有。

VIP(虚拟中断挂起) 虚拟中断挂起标志为Fentium~Pentium 4微处理器提供有关虚拟模式中断的信息。它用于多任务环境下,为操作系统提供虚拟中断和中断挂起信息。

  ID(标识)   标识标志指示Pentium-Pentium 4微处理器支持CPUID指令。CPUID指令给系统提供有关Pentium微处理器的信息,如版本号和制造商

段寄存器

其余的寄存器,段寄存器与其他寄存器一起合并生成内存地址。在众多微处理器中有的有四个段寄存器,有的有六个段寄存器。段寄存器在实模式和保护模式的功能不一。

CS(代码) 代码段是保存微处理器执行代码的内存段。代码段寄存器持有段的起始位置。在实模式它定义64K内存段的起始位置。在保护模式它选择一个描述符来描述段的起始位置和长度。在8088-80286上代码段的限制是64K,在80386以上的保护模式中它的大小是4G

DS(数据)     数据段是一个内存段,包括大多数的程序中使用的数据。数据段中的数据被通过偏移地址或者持有偏移地址的其他寄存器的内容访问。像代码段一样,它的大小在8088-80286上代码段的限制是64K,在80386以上的保护模式中是4G

ES(附加) 附加段是一个用来保存一些字符串指令的目标数据的附加数据段

SS(堆栈)     堆栈段定义了堆栈使用的内存区域。堆栈的入口地址由堆栈段和堆栈指针寄存器决定,BP寄存器也可以在堆栈寄存器里寻址。

   FSGS      这两个段是80386-Pentium4 微处理器中提供的段,来使程序得到两个附加段。Windows 用它完成一些内部操作,对它们没有明确的定义。


参考内容


    《Intel 微处理器英文第7版》

《汇编-32位寄存器的功能及其使用之整理篇》http://hi.baidu.com/shongbee2/blog/item/e3da9d38e053f72f97ddd888.html 


http://blog.chinaunix.net/uid-10014667-id-471549.html

http://www.cnblogs.com/zimmerk/articles/2520011.html


Logo

更多推荐