开始读Linux内核相关书籍时,在书店里碰到一个计算机专业科班出身的朋友,向他请教时,他认为学习Linux内核不需要汇编和计算机体系结构等相关的知识。可是结合到现在的学习经历,我却越来越觉得为了搞清楚Linux内核相关设计和运行原理,自己那点自学来的汇编知识不但不够,还大大的需要补充。本文是我今日对微处理器寄存器学习总结所得,主要是翻译自《Intel 微处理器英文第7版》,阅读的过程中我参考了网上可以下载到的该书第六版的中文版和一篇关于寄存器在Visual Stdio 编译器中惯用方法的文章《汇编-32位寄存器的功能及其使用之整理篇》一文,但是考虑之后没有将其大段引用。
编程模型
按位分类
8086的编程模型包括8、16和32位的寄存器。
八位的寄存器包括AH,AL,BH,BL,CH,CL,DH和DL。
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,EIP和EFLAGS。
所有的32位寄存器和16位寄存器中的FS或者GS都仅仅能够在80386以上使用。
按照用途分类
一些寄存器是通用寄存器或者多用途寄存器,而另外的一些则是特殊用途的寄存器。多用途寄存器包括EAX,EBX,ECX,EDX,EBP,EDI和ESI。这些寄存器都是可变大小的,并且能够被应用程序用于几乎所有的目的。
也有人按照用途将这些寄存器分为以下四类:
4个数据寄存器(EAX、EBX、ECX和EDX)
2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)
6个段寄存器(ES、CS、SS、DS、FS和GS)
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位(AH,HL)。注意如果8位或者16位寄存器被寻址,则仅仅会改变32位寄存器的一部分而不会影响到其他部分。累加器可以被用来做加减乘除这样的指令也可以被用作一些调整指令。对于这些调整指令,累加器具备一个特殊目的,但是它仍然通常被认为是多用途寄存器。在80386之上的微处理器(注意不是所有版本)中,EAX寄存器也可以持有内存系统地址的偏移地址。
EBX (基索引) EBX可以被作为EBX、BX,BH和BL被寻址,在所有版本的微处理器(包括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也可以起到通用寄存器的作用。
特殊目的寄存器
特殊目的寄存器包括EIP,ESP和EFLAGS;和段寄存器CS,DS,ES,SS,GS。
EIP(指令指针) EIP寻址作为代码段定义的内存段中的下一个指令。该寄存器是实模式下的IP指令和80386以上的保护模式中的EIP指令。注意8086,8088,和80286不包含EIP寄存器,仅仅80286以上的寄存器有保护模式。指令指针指向程序的下一条指令,被微处理器用来寻找代码段中下一个序列指令。指令指针可以被通过jump或者call指令修改。
ESP(堆栈指针) ESP寻址被称为堆栈的内存区域。堆栈内存以指针的形式存储数据并且在下文寻址堆栈数据的指令里得到解释。该寄存器用在16位是SP,用在32位是ESP。
EFLAGS EFLAGS指示微处理器的条件并且控制它的操作。下图显示了微处理器所有版本的注册器标志。注意这些标志都是后向兼容的。8086-80286拥有一个FLAG寄存器80386以上包括一个EFLAG寄存器(将标志扩展到32位)。
最右边的信号的五个位和溢出标志会在多个算数和逻辑指令执行之后会被改变。这些所有的标志对于数据传递和程序控制都是不被改变的。一些标志也被用来在微处理器中控制特征。最右边的五个信号会被大多数的算数运算和逻辑运算改变,但仍然不会被数据传递和逻辑操作改变。
C(进位) 进位标志保存加法以后的进位或减法以后的借位,也可以用进位标志
指示由某些程序或进程引发的错误条件,这在DOS功能调用尤其有用。
P (奇偶性) 奇偶标志表示结果数中1的个数是奇数还是偶数,是奇数则该标志
是逻辑0,是偶数则该标志是逻辑to如果某个二进制数含有3个
为I的位,它的奇偶性为奇数。如果某个二进制数包含O个为l的
位、它的奇偶性为偶数。奇偶性标志在现代程序设计中很少使用,
它是早期I}tet微处理器在数据通信环境中校验数据的一种手段。今
天,奇偶校验常常由数据通信设备完成,而不是由微处理器完成。
A(辅助进位)辅助进位标志保存加法后的结果中第3位与第4位之间的进位(半
进位),或者减法后的结果中第3位与第4位之间的借位。D DA和
BAS指令测试这个特殊标志位,以便在BCD加法或减法后对AL
中的值进行十进制调整。除此以外,微处理器或者任何其他指令都
不使用A标志位。
Z (零) 零标志表示一个算术或逻辑操作的结果是否为0。如果Z=1,表示
结果为0如果Z=0,表示结果不为0。
S (符号) 符号标志存放算术或逻辑运算指令执行后结果的算术符号。如果S=1, 则符号位(数的最左一位)为1或为负;如果S=0,则符号位为0或为正。
T (捕捉) 陷阱标志能够激活微处理器芯片上的调试功能(对程序进行调试,
以便找到错误或故障)。如果T标志为允许(为1),则微处理器根
据调试寄存器和控制寄存器的指示中断程序流。如果T标志为0,
则禁止捕捉(调试)性能。VC 程序可以利用陷阱特性和调试寄存器调 试有缺陷的软件。
I (中断) 中断标志控制INT(中断请求)输人开关的操作。如果I=1,则INTR开 关被允许,如果ICU,则INTR引脚被禁止。I标志的状态由SLI(置位 I标志)和CLI(清除I标志)指令控制。
D (方向) 在串指令操作期间,方向标志为DI和SI寄存器选择递增方式或递
减方式。如果D=1.则寄存器内容自动地递减;如果D=0,则寄存器内容 自动地递增。D标志用STD (置位方向)指令置位,用CLD(清除方向) 指令清除。
O (溢出) 溢出标志在有符号数进行加或减时可能出现。溢出指示运算结果已
超出机器能够表示的范围。对于无符号的操作,不考虑溢出标志。
IOPL(I/O优先级)输人/输出优先级标志用于保护模式操作时为刀。设备选择优先级。
如果当前任务的优先级高于工IOPL,则到O指令能顺利执行如果
IOPL比当前任务的优先级低。则产生中断,导致执行程序被挂起。
注意,00级是最高优先级,11级是最低优先级。
NT(任务嵌套) 任务嵌套标志指示在保护模式下当前执行的任务嵌套于另一任务
中。当任务被软件嵌套时,这个标志置位。
RF(恢复) 恢复标志和调试寄存器一起使用,控制在下条指令后恢复程序的
执行。
VM(虚拟方式)虚拟方式标志用于在保护模式系统中选择虚拟操作模式。虚拟模式
系统允许多个1 MH长的DOS存储器分区共存于存储器系统中。这
样可以允许系统执行多个DOS程序。
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寄存器也可以在堆栈寄存器里寻址。
FS和GS 这两个段是80386-Pentium4 微处理器中提供的段来程序得到两个附加段。Windows 用它完成一些内部操作,对它们没有明确的定义。
参考内容
《Intel 微处理器英文第7版》
《汇编-32位寄存器的功能及其使用之整理篇》http://hi.baidu.com/shongbee2/blog/item/e3da9d38e053f72f97ddd888.html