寄存器(registor)是CPU内部用来存放数据的一些小型存储区域,它与我们常常说的RAM(Random Access Memory,随机存储器、内存)略有不同。CPU访问(Access)RAM中的数据时要经过较长的物理路径,所以花费的时间要长一些;而寄存器集成在CPU内部拥有非常高的读写速度。大部分汇编指令用于操作寄存器或检查其中的数据,必须掌握寄存器相关的内容才能真正明白这些汇编指令的含义。

基本程序运行寄存器

基本程序运行寄存器的组织结构,它由4类寄存器组成
通用寄存器(General Purpose Registers,32位,8个)EXA、EBX、ECX、EDX、EBP、ESP、ESI、EDI
段寄存器(Segment Registers,16位,6个)CS、DS、SS、ES、FS、GS
程序状态与控制寄存器(Program Status and Control Register,32位,1个)EFLAGS
指令指针寄存器(Instruction Pointer,32位,1个)EIP
GV4YS0GIRGV]T8S$G6PDK)F.png

1、通用寄存器

通用寄存器是一种通用型的寄存器,用于传送和暂存数据,也可以参与算术逻辑运算,并保存运算结果。IA-32中每个通用寄存器的大小都是32位,即4个字节,主要用来保存常量与地址等, 由特定汇编指令来操作特定寄存器。除常规用途外,某些寄存器还具有一些特殊功能。
![16AY{}A}Y~63X~T%60T$P6.png
为实现对低16位打的兼容,各寄存器又可以分为高(H:High)、低(L:Low)几个独立寄存器。以EAX为例。
EAX:(0~31)32位
AX:(0~15)EAX的低16位
AH:(8~15)AX的高8位
AL:(0~7)AX的低8位
若想全部使用4个字节(32位),则使用EAX;若只想用2个字节(16位),只要使用EAX的低16位部分AX即可
AX又分为高8位的AH与低8位的AL两个独立寄存器。借助这种方式,可以根据不同情况把一个32位的寄存器分别用作8位、16位、32位寄存器。
各寄存器的名称如下所示。
EAX:(针对操作数和结果数据的)累加器
EBX:(DS段中的数据指针)基址寄存器
ECX:(字符串和循环操作的)计数器
EDX:(I/O指针)数据寄存器
以上4个寄存器主要用在算术运算(ADD、SUB、XOR、OR等)指令中,常常用来保存在常量与变量的值。某些汇编指令(MUL、DIV、LODS等)直接用来操作特定寄存器,执行这些命令后,仅改变特定寄存器的值。
此外,LOOP命令中,ECX用来循环计数(loop count),没执行一次循环ECX都会减1。EAX一般用在函数返回值中,所有Win32API函数都会先把返回值保存到EXA再返回。
注意:编写Windows汇编程序时,Win32API函数在内部会使用ECX与EDX,调用这些API时,ECX与EDX的值就会改变。所以,ECX与EDX中保存有重要数据时,调用API前要先把这些数据备份到其他寄存器或栈。
通用寄存器中其他几个寄存器的名称如下所示。
EBP:(SS段中栈内数据指针)扩展基址指针寄存器
ESI:(字符串操作源指针)源变址寄存器
EDI:(字符串操作目标指针)目的变址寄存器
ESP:(SS段中栈指针)栈指针寄存器
以上4个寄存器主要用作保存内存地址的指针。
ESP指示栈区域的栈顶地址,某些指令(PUSH、POP、CALL、RET)可以直接用来操作ESP(不要把ESP用作其他用途)。
EBP表示栈区域的基地址,函数被调用时保存ESP的值,函数返回时再把值返回ESP,保证栈不会崩溃(称为栈帧(Stack Frame)技术)。ESI和EDI与特定指令(LODS、STOS、REP、MOVS等)一起使用,主要用于内存复制。

2、段寄存器

IA-32的保护模式中,段是一种内存保护技术,它把内存划分为多个区段,并为每个区段赋予起始地址、范围、访问权限等,以保护内存。此外,它还同分页技术(Paging)一起用于将虚拟内存变更为实际物理内存。段内存记录在SDT(Segment Descriptor Table,段描述表)中,而段寄存器就持有这些SDT的索引(index)。
段寄存器共由6种寄存器组成,分别为CS、SS、DS、ES、FS、GS,每个寄存器的大小为16位,即2个字节。另外,每个段寄存器指向的段描述符(Segment Descriptor)与虚拟内存结合,形成一个线性地址(Linear Address),借助分页技术,线性地址最终被转换为实际的物理地址(Physical Address)。不使用分页技术的操作系统中,线性地址直接变为物理地址。
各段寄存器的名称如下
CS:Code Segment,代码段寄存器
SS:Stack Segment,栈段寄存器
DS:Data Segment,数据段寄存器
ES:Extra(Data) Segment,附加(数据)段寄存器
FS:Data Segment,数据段寄存器
GS:Data Segment,数据寄存器
顾名思义,CS寄存器用于存放应用程序代码所在段的段基址,SS寄存器用于存放栈段的段基址,DS寄存器用于存放数据段的段地址。ES、FS、GS寄存器用来存放程序使用的附加数据段的段基址
image.png
其中FS寄存器用于计算SEH(Structured Exception Hanler,结构化异常处理机制)、TEB(Thread Environment Block,线程环境块)、PEB(Process Environment Block,进程环境块)等地址。

3、程序状态与控制寄存器

EFLAGS:Flag Register,标志寄存器
IA-32中标志寄存器EFLAGS其大小为4个字节(32位),由原来的16位FLAGS寄存器扩展而来。EFALG寄存器每位都有意义,每位的值为1或0,代表On/Off或TRUE/FALSE。其中有些位由系统直接设定,有些位则根据程序的命令的执行结果设置。
EFLAG寄存器共有32个位元,目前只需掌握3个标志:ZF(Zero Flag,零标志)、OF(Overflow Flag,溢出标志)、CF(Carry Flag,进位标志)。以上3个标志之所以重要,是因为在某些汇编指令,特别是Jcc(条件跳转)指令中要检查这3个标志的值,并根据它们的值决定是否执行某个动作。
]8F$`$8C5H``NQKWY00097D.png
ZF:若运算结果为0,则其值为1(True),否则其值为0(False)。
OF:有符号整数(signed integer)溢出时,OF值被置为1。此外,MSB(Most Significant Bit,最高有效位 )改变时,其值也被设为1。
CF:无符号整形(unsigned integer)溢出时,其值也被置为1。

4、指令指针寄存器

EIP:Instruction Pointer,指令指针寄存器
指令指针寄存器保存着CPU要执行的指令地址,其大小为32位(4个字节),由原16位IP寄存器扩展而来。程序运行时,CPU会读取EIP中一条指令的地址,传送指令到指令缓冲区后,EIP寄存器的值自动增加,增加的大小即是读取指令的字节大小。这样,CPU每次执行完一条指令,就会通过EIP寄存器读取并执行下一条指令。
与通用寄存器不同,我们不能直接修改EIP的值,只能通过其他指令间接修改,这些特定指令包括JMP、Jcc、CALL、RET。此外,我们还可以通过中断或异常来修改EIP的值。