本文主要以《Intel® 64 and IA-32 Architectures Software Developer’s Manual》(下文简称《手册》)为依据,对 IA-32 架构中涉及的寄存器进行列举、学习和总结。
寄存器分类
Basic Program Execution Registers1
- General-purpose Registers
- Segment Registers
- EFLAGS (program status and control) Register
- EIP (instruction pointer) Register
System Registers2
- Memory-Management Registers
- Controll Registers
- Debug Registers (not shown in Figure 2-1)
- Model-specific Registers (not shown in Figure 2-1)
1.Basic Program Execution Registers(BPER)
@Vol-1 Section-3.4:
IA-32 architecture provides 16 basic program execution registers for use in general system and application programing.
从这段描述中可以看出,BPER 是提供给软件开发人员编程时使用的。16 个寄存器的结构和分类见下图:
1.1.通用寄存器
用途
通用寄存器通常用来保存算数/逻辑运算的操作数、地址计算操作数、内存地址(指针)、运算结果等。
此外,一些指令会使用特定的通用寄存器作为特殊用途来实现相应的功能,比如:
- 对于字节类型的乘法运算,
MUL
指令规定将被乘数设置到AL
中,并使用AX
保存运算结果; MOVSB
指令进行字符串拷贝时,根据DS:(E)SI
和ES:(E)DI
来确定源字符串和目标字符串的起始地址;REP 前缀
根据(E)CX
来确定其修饰的指令的重复执行次数
值得一提的是:(E)SP
的用途是保存当前栈的栈顶指针(CPU 在执行 push、pop
等指令的过程中会“内置的”修改它),所以我们在编程时要注意——避免将它作为其他用途使用!
@Vol-1 Section-3.4.1:
Although all of these registers are available for general storage of operands, results, and pointers, caution should be used when referencing the ESP register. The ESP register holds the stack pointer and as a general rule should not be used for another purpose.
此外,《手册》中对通用寄存器的特殊用途做了以下总结(按照这种规范来编程的好处:程序中寄存器的使用方式一致,可读性强!):
IA-32 中通用寄存器结构较 8086 发生的变化
通用寄存器的位宽由 16 位增加至 32 位,但支持向后兼容(如:8086 提供的 AX, AH, AL
还可以继续使用)。
关于 SI 和 DI
ESI, EDI
被称为变址寄存器,常被字符串操作指令3使用(通常配合 REP*
前缀)。
关于 SP 和 BP
SP
——Stack Pointer(栈指针),用来记录当前栈的栈顶地址。BP
——Stack-Frame Base Pointer, 顾名思义它的作用是在过程调用4中,能够直观的描述一个栈帧5(编译器通常会使用 BP
和 SP
之间的区域来表示当前栈帧)。
栈是内存中的一块连续空间(在分段内存管理模型中,这块空间被称为“堆栈段”)。处理器提供了 push
和 pop
指令,用于在这块空间上实现栈操作。具体的操作方法是:使用 push|pop
指令将数据压栈|弹栈
,它们会使 SP
进行移动。由于栈是向下(高地址向低地址)生长的,所以 push
会使 SP
向低地址移动,pop
则使其向高地址移动。初始时 SP
即表示栈顶也表示栈底。
系统中可以有多个“堆栈段”,将一个堆栈段切换成当前栈所要做的事情就是将 SS, SP
设置正确。所以在 CPU 眼里,与当前栈相关联的寄存器只有 SS, SP
——根据 SS
来确定这个堆栈段的起始地址,根据 SP
来确定当前栈的使用情况。(为什么在 CPU 眼中没有 BP
呢?大家不妨思考一下!)下图中描述了将一个栈切换成“当前栈”时需要做的事情:
1.2.指令指针寄存器
该寄存器的作用是存储下一条要执行指令的偏移位置,通常在取指阶段的最后环节对其进行更新。
1.3.标志寄存器
标志寄存器中的每一位为一个标志位,在 32 位的 EFLAGS
中标志位分为三类:状态标志、控制标志和系统标志。如下图所示:
- 状态标志:记录在一条指令执行完后产生的状态信息。比如:是否产生进位、是否发生溢出、符号位是什么、计算结果是否等于 0……有条件转移指令通常基于这些状态位进行跳转。
- 控制标志:控制应用程序的执行方式。比如:
DF 位
可以控制数据拷贝时,是由低地址向高地址还是高地址向低地址拷贝,可以避免源地址空间与目的地址空间有部分重叠时所带来的数据覆盖问题。 - 系统标志:控制系统级程序或硬件的工作方式。
1.4.段寄存器
在 IA-16 和 IA-32 架构中,段寄存器都是 16 位。
- IA-16 中提供的段寄存器:
CS
、DS
、SS
、ES
- IA-32 中新增了
FS
和GS
, 注:DS
,SS
,ES
,FS
,GS
都属于数据段寄存器,其实代码也可以作为数据进行处理(都是二进制序列),只不过这些“数据”按照 ISA 规范编码,它们的重点是用于执行!
2.Memory-Management Registers6
GDTR、IDTR
它俩的结构相似,分成了两部分
第一部分:保存 GDT、IDT 表在线性地址空间的首地址
第二部分:保存 GDT、IDT 表所占的字节数
TR、LDTR
它俩的结构相似,并且与段寄存器 (CS, DS, SS, ES, FS, GS) 的结构类似,保存了以下信息:
- 段选择子
缓存相应的段描述符中的段基址(对应段在线性地址空间中的首地址)
- TR 中缓存的是当前执行任务的 TSS 信息在线性地址空间中的首地址
- LDTR 中缓存的是当前执行任务的 LDT 数据段在线性地址空间中的首地址
- 缓存 segment limit, and descriptor attributes 信息
注:在任务切换时,这两个寄存器必须被更新
3.Controll Registers7
- CR0
- CR1
- CR2
- CR3
- CR4
- CR8
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。