这部分主要介绍了主要的IA-32系列处理器以及著名的保护方式和实地址方式的工作模式。
首先明确IA-32系列处理器是什么:
IA-32系列处理器泛指基于英特尔IA-32架构的32位微处理器
代表的型号比如:
其最大特点是保持了与先前处理器的兼容。
保护方式是IA-32系列处理器的常态工作方式,只有在保护方式下, IA-32系列处理器才能发挥出其全部性能和特点 。
windows和Linux都运行于保护方式。
保护方式的主要特点:
实地址方式(Real-address mode)是最初的工作方式,是处理器重新开始运行后的最初工作方式。
实地址方式是IA-32系列处理器中最初的处理器的工作方式(最早的8086/8088只能工作在实地址方式,因为其没有保护方式)。
实地址方式的特点:
关于寄存器的几点注意点:
寄存器是处理器内的特殊存储单元。
处理器内有多种不同用途的寄存器。
寄存器分别有各自的名称,以便表示及访问。
IA-32系列CPU有8个32位通用寄存器:EAX、 EBX、 ECX、 EDX、 ESI、 EDI、 EBP、 ESP
主要功能:存储数据、参与算术逻辑运算、给出存储单元的地址。
注意: 可以单独直接访问这些通用寄存器的低16位,他们是8个16位通用寄存器,名称分别是:AX、BX、CX、DX、SI、DI、BP、SP,对应16位处理器Intel 8086的8个通用寄存器。
还可以单独直接访问AX、BX、CX、DX的高8位和低8位,示意图如下:
带H的寄存器(比如AH、BH)代表的是X寄存器(AX、BX)的High(高)字节,对应的,AL代表的就是AX的Low(低)字节。
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
MOV | 传送指令 | MOV DEST,SRC | DEST<=SRC | 源和目标的尺寸必须一致,不能同时是存储单元。 |
XCHG | 交换指令 | XCHG OPER1,OPER2 | 把操作数oper1的内容与操作数oper2的内容交换 | oper1和oper2可以是通用寄存器或存储单元,但不能同时是操作单元,也不能是立即数,也不能同时是存储单元。 |
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
ADD | 加法指令 | ADD DEST,SRC | DEST<=DEST SRC | 两数相加 |
SUB | 减法指令 | SUB DEST,SRC | DEST<=DEST-SRC | 两数相减 |
INC | 加1指令 | INC DEST | DEST<=DEST 1 | |
DEC | 减1指令 | DEC DEST | DEST<=DEST-1 | |
NEG | 取补指令 | NEG OPRD | OPRD=0-OPRD | 对操作数取补(相反数) |
标志寄存器是一个32位的寄存器,主要反映处理器的状态和运算结果的某些特征,认为主要是状态标志和控制标志以及系统标志三部分。
如上图所示,标两个字母的是状态标志位,标着X的是系统标志位,标着字母C的是控制标志位,阴影部分是不使用的保留位。
标志 | 标志名 | 主要功能 |
---|---|---|
CF | 进位标志(Carry flag) | 当算术运算产生进位或者借位时,置标志(1),否则清标志(0)。 |
SF | 符号标志(Sign flag) | 反映运算结果的符号位(符号位为1,置标志;否则清),与运算结果的最高位相同。 |
ZF | 零标志(Zero flag) | 当运算结果为0时,置标志;否则清标志。 |
OF | 溢出标志(Overflow flag) | 反映有符号数的加减运算是否引起溢出,如果溢出,置标志,否则清标志。 |
PF | 奇偶标志(Parity flag) | |
AF | 辅助进位标志(Auxiliary Carry flag) |
指令 | 中文名 | 格式 | 解释 |
---|---|---|---|
CLC(clear carry flag) | 清进位标志指令 | CLC | 使进位标志CF为0 |
STC(set carry flag) | 置进位标志指令 | STC | 使进位标志CF为1 |
CMC(complement carry flag) | 进位标志取反指令 | CMC | 使进位标志CF取反 |
LAHF(load status flags into AH register) | 获取状态标志操作指令 | LAHF | 把位于标志寄存器低端的8位同时送到寄存器AH的对应位 |
SAHF(store AH into Flags) | 设置状态标志操作指令 | SAHF | 对标志寄存器中的低8位产生影响,使得状态标志位SF、ZF、AF、PF和CF分别成为来自寄存器AH中对应位的值,但保留位(位1、位3、位5)不受影响 |
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
ADC(add with carry) | 带进位加法指令 | ADC DEST,SRC | DEST<=DEST SRC CF | 与add指令不同之处是要再加上进位标志cf的值 |
SBB(substraction with borrow) | 带借位减法 | SBB DEST,SRC | DEST<=DEST-(SRC CF) | 与sub指令不同之处是要再减上借位标志cf的值 |
CPU能够通过其总线直接寻址访问的存储器 被称为内存,每一个字节存储单元有一个唯一的地址,称之为物理地址。
CPU的地址线数量决定了可产生的最大物理地址, n根地址线,可形成的最大物理地址是 2 n 2^n 2n-1,所有可形成的物理地址的集合被称为物理地址空间.
物理地址空间大小不等于实际安装的物理内存大小。
为了有效地管理存储器,常常把地址空间划分为若干逻辑段, 对应存储空间被划分为若干存储段。逻辑段和存储段是一致的。
一般说来,运行着的程序在存储器中映像有三部分组成:
代码,代码是要执行的指令序列;
数据,数据是要处理加工的内容;
堆栈,堆栈是按“先进后出”规则存取的区域。
通常,代码、数据和堆栈分别占用不同的存储器段,相应的段也就被称为代码段、数据段和堆栈段。
在分段之后,程序中使用的某个存储单元总是属于某个段。 所以,可以采用某某段某某单元的方式来表示存储单元。
在程序中用于表示存储单元的地址被称为逻辑地址。
由于采用分段存储管理方式,程序中使用的逻辑地址是二维的,第一维给出某某段,第二维给出段内的某某单元。
二维的逻辑地址: 段号∶偏移
在实方式和保护方式下,都通过偏移指定段内的某某单元。在实方式下,段号是段值;在保护方式下,段号则是段选择子。
逻辑地址转换为物理地址的过程为由段号得到段起始地址,再加上偏移。
需要注意的是;
保护方式下,物理地址是32位,段起始地址是32位,偏移是32位;
在实方式下,物理地址是20位,段起始地址是20位,偏移是16位。
逻辑地址中的段号(段值或者段选择子)存放在哪里呢?
答案是,当前使用段的段号存放在段寄存器(Segment Registers)中。
段寄存器名称 | 中文名 | 解释 | 出现时期 |
---|---|---|---|
CS(Code Segment) | 代码段寄存器 | 当前代码段 | Intel 8060处理器 |
SS(Stack Segment) | 堆栈段寄存器 | 当前堆栈段 | Intel 8060处理器 |
DS(Data Segment) | 数据段寄存器 | 当前数据段 | Intel 8060处理器 |
ES(Extra Segment) | 附加段寄存器 | 可用于指定数据段 | Intel 8060处理器 |
FS | 附加段寄存器 | 可用于指定数据段 | 80386开始 |
GS | 附加段寄存器 | 可用于指定数据段 | 80386开始 |
表示指令中操作数所在的方法称为寻址方式,主要分为三大类:
此外还有固定寻址和I/O端口寻址等
说白了当操作数是立即数的时候就是立即寻址方式,比如:
mov eax,12345678H
所以:
就是操作数在CPU内部的寄存器中,指令中指定寄存器,不需要通过访问存储器来取得操作数,所以采用寄存器寻址方式的指令执行速度较快。
当指令的操作数在存储单元时,指定存储单元就指定了操作数。
为了灵活地访问存储器,IA-32系列CPU提供了多种表示存储单元偏移的方式,即有多种存储器寻址方式:
操作数在存储器中,指令直接包含操作数所在存储单元的有效地址。
mov ecx,[95480H]
操作数在存储器中,由八个32位通用寄存器之一给出操作数所在存储单元的有效地址。
寄存器间接寻址方式中,给出操作数所在存储单元有效地址的寄存器相当于c语言中的指针变量,它含有要访问存储单元的地址。
mov ecx,[esi]
存储单元的有效地址可以由三部分内容相加构成:
这三部分可省去任意的两部分。
add dx,[ecx 5328H]//寄存器相对寻址方式
xchg [ebx,esi],dx//基址加变址寻址方式
mov ebx,[edi eax*4 300H]//基址加放大因子的变址寻址方式
在某条具体的指令中,如果有存储器操作数,那么其尺寸是确定的。在大多数情况下,存储器操作数的尺寸是一 目了然的,因为通常要求一条指令中的多个操作数的尺寸 一致,所以指令中的寄存器操作数的尺寸就决定了存储器操作数的尺寸。在少数情况下,需要显式地指定存储器操作数的尺寸。
LEA EBX, bufi
MOV DWORD PTR [EBX], 5 // 双字
MOV WORD PTR [EBX 4], 5 //字
MOV BYTE PTR [EBX 8], 5 //字节
如果基址寄存器不是EBP或者ESP,那么缺省引用的段寄存器是DS;
如果基址寄存器是EBP或者ESP,那么缺省引 用的段寄存器是SS。
当EBP作为变址寄存器使用(ESP不 能作为变址寄存器使用)时,缺省引用的段寄存器仍然是 DS。
无论存储器寻址方式简单或者复杂,如果由基址寄存器、 带比例因子的变址寄存器和位移量这三部分相加所得超过 32位,那么有效地址仅为低32位。
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
LEA(load effective address) | 取有效地址指令 | LEA REC,OPRD | 把操作数oprd的有效地址传送到操作数rec,源操作数oprd必须是一个存储器操作数,目的操作数rec必须是一个16位或32位的通用寄存器 | 与mov指令的区别:mov:移动地址中的值lea:将地址进行移动 |
lea指令的妙用:
IA-32系列CPU有一个32位的指令指针寄存器EIP,由CS和EIP确定所取指令的存储单元地址。段寄存器CS给出当前代码段的段号,指令指针寄存器EIP给出偏移。
实方式下,段的最大范围是64K,EIP中高16位必须是0,相当于只有低16位的IP起作用。
CPU 执行代码(程序)就是一条接一条地执行机器指 令。可以把CPU执行指令的过程看作一条处理指令的流水线,其第一步是从存储器中取出指令。在取出一条指令后,会根据所取指令的长度,自动调整指令指针寄存器 E I P 的值,使其指向下一条指令。这样,就实现了顺序执⾏指令。
那么如果我们不想顺序执行指令,而想非自动顺序调整EIP的内容,这就是所谓的转移。
衍生出的控制转移指令就是专门用于改变EIP内容的指令,主要包括:
这些控制转移指令的实质就是根据不同的情形改变EIP的内容以实现转移。
所谓条件转移指,当某一条件满足时,发生转移,否则继续顺序执行。换句话说,当某一条件满足时,就改变 EIP的内容,从而实施转移,否则顺序执行 。
标志寄存器中的状态标志被用于表示条件。绝大部分条件转移指令根据某个标志或者某几个标志来判断条件是否满足。
条件转移类似于高级语言的分支。
主要可以分为三类:
指令格式 | 转移条件 | 转移说明 | 其他说明 |
---|---|---|---|
JZ 标号 JE 标号 | ZF=1 同上 | 等于0转移(Jump if zero) 相等转移(Jump if equal) | 单个标志 |
JNZ 标号 JNE 标号 | ZF=0 同上 | 不等于0转移(Jump if not zero) 不相等转移(Jump if not equal) | 单个标志 |
JB 标号 JNAE 标号 JC 标号 | CF=1 同上 同上 | 低于转移 不高于等于转移 进位位被置转移 |
单个标志 (无符号数) |
JNBE 标号 JA 标号 | (CF或ZF)=0 同上 | 不低于等于转移 高于转移 | 两个标志 (无符号数) |
JLE 标号 JNG 标号 | ((SF异或OF)或ZF)=1 同上 | 小于等于转移 不大于转移 | 三个标志 (有符号数) |
JNLE 标号 JG 标号 | ((SF异或OF)或ZF)=1 同上 | 不小于等于转移 大于转移 | 三个符号(有符号数) |
条件转移指令本身不影响标志。
条件转移指令在条件满足的情况下,只改变指令指针寄存器EIP。也就是说,条件转移的转移目的地仅限于同一个代码段内。这种不改变代码段寄存器CS,仅改变EIP的 转移被称为段内转移。
条件转移指令可以实现向前方转移,也可以实现向后方 转移。
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
CMP | 比较指令 | CMP DEST,SRC | 根据dest-src的差影响各状态标志寄存器 | 不把dest-src的结果送入dest |
比较指令是根据DEST-SRC的差影响标志寄存器的各状态标志(但不把结果送到DEST中)来判断两个数的大小关系的,判断的准则如下:
根据零标志ZF是否置位,判断两者是否相等;
如果两者是无符号数,可根据进位标志CF判断大小;
如果两者是有符号数,要同时根据符号标志SF和溢出标志OF判断大小。
为了方便进行数值大小比较,IA-32系列CPU提供两套以数值大小为条件的条件转移指令,一套适用于无符号数之间的比较,另一套适用于有符号数之间的比较:
有符号数间的次序关系称为大于(G)、等于(E) 和小于(L);
无符号数间的次序关系称为高于(A)、等于(E)和低于(B);
类似于高级语言中的goto语句,就是jmp语句:
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
JMP | 无条件段内直接转移指令 | JMP LABEL | 使控制无条件地转移到标号为label的位置 | 无条件转移指令本身不影响标志 |
所谓堆栈其实就是一段内存区域,只是对它的访问操作仅限于一端进行,地址较小的一端被称为栈顶,地址较大的一端被称为栈底。
堆栈段寄存器SS含有当前堆栈段的段号,SS指示堆栈所在内存区域的位置。 堆栈指针寄存器ESP含有栈顶的偏移(有效地址),ESP指向栈顶。
堆栈的主要用途:
指令 | 中文名 | 格式 | 解释 | 备注 |
---|---|---|---|---|
PUSH | 进栈指令 | PUSH SRC | 把源操作数src压入堆栈 | 源操作数src可以是32位通用寄存器、16位通用寄存器和段寄存器,也可以是双字存储单元或者字符存储单元,还可以是立即数 |
POP | 出栈指令 | POP DEST | 从栈顶弹出一个双字或字数据到目的操作数 | 如果目的操作数是双字的,那么就从栈顶弹出一个双字数据,否则,从栈顶弹出一个字数据,出栈至少弹出一个字(16位) |
PUSHA | 16位通用寄存器全进栈指令 | PUSHA | 将所有8个16位通用寄存器的内容压入堆栈 | 压入顺序是AX CX DX BX SP BP SI DI,然后对战指针寄存器SP的值减16,所以SP进栈的内容是PUSHA指令执行之前的值 |
POPA | 16位通用寄存器全出栈指令 | POPA | 以PUSHA相反的顺序从堆栈中弹出内容,从而恢复PUSHA之前的寄存器状态 | SP的值不是由堆栈弹出的,而是通过增加16来恢复 |
PUSHAD | 32位通用寄存器全进栈指令 | PUSHAD | 将所有8个32位通用寄存器的内容压入堆栈 | 压入顺序是EAX ECX EDX EBX ESP EBP ESI EDI,然后对战指针寄存器SP的值减32,所以SP进栈的内容是PUSHAD指令执行之前的值 |
POPAD | 32位通用寄存器全出栈指令 | POPAD | 以PUSHAD相反的顺序从堆栈中弹出内容,从而恢复PUSHAD之前的寄存器状态 | ESP的值不是由堆栈弹出的,而是通过增加32来恢复 |