学习参考:汇编语言(第2版)王爽
- 通用寄存器
- 字在寄存器中的存储
- 几条汇编指令
- 物理地址
- 16 位结构的 CPU
- 8086CPU 给出物理地址的方法
- “段地址*16+偏移地址=物理地址” 的本质含义
- 段的概念
- 段寄存器
- CS 和 IP
- 修改 CS、IP 的指令
- 代码段
- 小结
一个典型的 CPU 由元算器、控制器、寄存器等器件构成,这些器件靠内部总线相连。在 CPU 中:
- 运算器进行信息处理
- 寄存器进行信息存储
- 控制器控制各种器件进行工作
- 内部总线连接各种器件,在它们之间进行数据的传送
8086CPU 有 14 个寄存器,每个寄存器有一个名称。这些寄存器是:
AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW
通用寄存器
8086CPU 的所有寄存器都是 16 位的,可以存放两个字节。AX、BX、CX、DX 这 4个存储器通常用来存放一般性到的数据,被称为通用寄存器
一个 16 位寄存器可以存储一个 16 位的数据。8086CPU 的 AX、BX、CX、DX 这 4 个寄存器都可分为两个可独立使用的 8 位寄存器来用:
- AX 可分为 AH 和 AL
- BX 可分为 BH 和 BL
- CX 可分为 CH 和 CL
- DX 可分为 DH 和 DL
以 AX 为例, 8086CPU 的 16 位寄存器分为两个 8 位寄存器的情况
AX 的低 8 位 (0位 ~ 7位)构成了 AL 寄存器, 高 8 位(8位 ~ 15位)构成了 AH 寄存器。AH 和 AL 寄存器可以独立使用的 8 位寄存器。下图为 16位寄存器及它所分成的两个 8 位寄存器的数据存储的情况,在 AH 中存储了它的高 8 位,在 AL 中存储了它的低 8 位。
字在寄存器中的存储
8086CPU 可以一次性处理以下两种尺寸的数据
- 字节:记为 byte,一个字节由 8 个 bit 组成,可以存在 8 位寄存器中
- 字:记为 word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节
一个字可以存在一个 16 位寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高 8 位寄存器和低 8 位寄存器中
几条汇编指令
通过汇编指令控制 CPU 进行工作
汇编指令举例
汇编指令 | 控制 CPU 完成的操作 | 用高级语言的语法描述 |
---|---|---|
mov ax,18 | 将 18 送入寄存器 AX | AX=18 |
mov ah,78 | 将 78 送入寄存器 AH | AH=78 |
add ax,8 | 将寄存器 AX 中的数值加上 8 | AX=AX+8 |
mov ax,bx | 将寄存器 BX 中的数据送入寄存器 AX | AX=BX |
add ax,bx | 将 AX 和 BX 中的数值相加,结果存在 AX 中 | AX=AX+BX |
程序段中指令的执行情况之一(原 AX 中的值:0000H,原 BX 中的值:0000H)
程序段中的指令 | 指令执行后 AX 中的数据 | 指令执行后 BX 中的数据 |
---|---|---|
mov ax,4E20H | 4e20H | 0000H |
add ax,1406H | 6226H | 0000H |
mov bx,2000H | 6226H | 2000H |
add ax,bx | 8226H | 2000H |
mov bx,ax | 8226H | 8226H |
add ax,bx | 044cH | 8226H |
因为 8226H + 8226H = 1044CH ,但是 ax 为 16 位寄存器,只能存放 4 位十六进制的数据,所以最高位的 1 不能在 ax 中保存, ax 中的数据为: 044CH
在对 al, ah 进行操作时,注意,此是 al 是作为一个独立的 8 位寄存器来使用的,和 ah 没有关系, CPU 在执行这条指令时认为 ah 和 al 是两个不相关的寄存器,如果操作数超过范围则高位会丢失
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的
物理地址
CPU 访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址
CPU 通过地址总线送入存储器的,必须是一个内存单元的物理地址。在 CPU 想地址总线上发出物理地址之前,必须要在内部先形成这个物理地址
16 位结构的 CPU
16 位结构描述了一个 CPU 具有下面几方面的结构特性:
- 运算器一次最多可以处理 16 位的数据
- 寄存器的最大宽度为 16 位
- 寄存器和运算器之间的通路为 16 位
在 8086 内部, 一次性处理、传输、暂时存储的信息的最大长度是 16 位的
8086CPU 给出物理地址的方法
8086CPU 有 20 位地址总线,可以传送 20 位地址,达到 1MB 寻址能力。8086CPU 是 16 位结构的, 一次性处理、传输、暂时存储的信息的最大长度是 16 位的。从内部结构看,如果将地址从内部简单地发出,那么它只能送出 16 位的地址,表现出的寻址能力只有 64 KB
8086CPU 采用一种在内部用两个 16 位地址合成的方法来形成一个 20 位的物理地址
- CPU 中的相关部件提供连两个 16 位的地址,一个称为段地址,一个称为偏移地址
- 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件
- 地址加法器将两个 16 位地址合成为一个 20 位的物理地址
- 地址加法器通过内部总线将 20 位物理地址送入输入输出控制电路
- 输入输出控制电路将 20 位物理地址送上地址总线
- 20 位物理地址被地址总线送到存储器
地址加法器采用 物理地址=段地址*16+偏移地址 的方法用段地址和偏移地址合成物理地址。
一个十六进制的数据左移 1 位,相当于乘以 16
一个 X 进制的数据左移 1 位,相当于乘以 X
“段地址*16+偏移地址=物理地址” 的本质含义
CPU 在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地质的偏移地址相加,给出内存单元的物理地址
段的概念
内存并没有分段,段的划分来自于 CPU,我们可以用分段的方式来管理内存
地址 10000H ~ 100FFH 的内存单元组成一个段,该段的起始地址为 10000H,段地址为 1000H 大小为 100H
注意
- CPU 可以用不同的段地址和偏移地址形成同一个物理地址
- 偏移地址 16 位,变化范围为 0~FFFFH,仅用偏移地址来寻址最多可寻 64KB 个内存单元
“数据在 21F60H 内存单元中” 的一般说法是:
- 数据存在内存 2000:1F60 单元中
- 数据存在内存的 2000 段中的 1F60 单元中
段寄存器
段地址在 8086CPU 的段寄存器中存放。8086CPU 有 4 个段寄存器:CS、DS、SS、ES。当 8086CPU 要访问内存时由这 4 个段寄存器提供内存单元的段地址
CS 和 IP
CS 和 IP 是 8086CPU 中两个最关键的寄存器,它们指示了 CPU 当前要读取指令的地址
- CS : 代码段寄存器 (Code Segment register)
- IP : 指令指针寄存器 (Instruction Pointer register)
在 8086CPU 机中,任意时刻,设 CS 中的内容为 M,IP 中的内容为 N,8086CPU 将从内存 M*16+N 单元开始,读取一条指令并执行。即任意时刻,CPU 将 CS:IP 指向的内容当作指令执行
8086CPU 的工作过程可以简要描述如下:
- 从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲器
- IP=IP+所都去指令的长度,从而指向下一条指令
- 执行指令。转到(1),重复这个过程
Q:CPU 根据什么将内存中的信息看作指令?
A:CPU 将 CS:IP 指向的内存单元中的内容看作指令,因为,在任何时候,CPU 将 CS、IP 中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。如果说,内存中的一段信息曾被 CPU 执行过的话,那么,它所在的内存单元必然被 CS:IP 指向过。
修改 CS、IP 的指令
在 CPU 中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对 CPU 的控制。CPU 从何处执行指令是由 CS、IP 中的内容决定的,程序员可以通过改变 CS、IP 中的内容来控制 CPU
8086CPU 大部分寄存器的值,都可以用 mov 指令来改变,mov 指令被称为传送指令
mov 指令不能用于设置 CS、IP 的值,因为 8086CPU 没有提供该功能
能够改变 CS、IP 的内容的指令被称为转移指令
一个简单的可以修改 CS、IP 的指令:JMP 指令。若想同时修改 CS、IP 的内容,可用形如
1 | jmp 段地址:偏移地址 |
的指令完成。其功能为:用指令中给出的段地址修改 CS,偏移地址修改 IP
例如
1 | jmp 2AE3:3 ;执行后:CS=2AE3H, IP=0003H, CPU 将从 2AE33H 处读取指令 |
若想仅修改 IP 的内容,可用形如
1 | jmp 某一合法寄存器 |
的指令完成。其功能为:用寄存器中的值修改 IP
例如
1 | jmp ax ;指令执行前:ax=1000H, CS=2000H, IP=0003H |
举个不恰当的比喻,这有点类似于 mov IP,ax
,当然这个指令是不存在的,不过可以这么理解
代码段
首先我们可以将长度为 N (N <= 64KB)的一组代码,存在一组地址连续、起始地址为 16 的倍数的内存单元中,可以认为这段内存是用来存放代码的,从而定义一个代码段。
那么如何使得代码段中的指令被执行?CPU 只认被 CS:IP 指向所定义的代码段中的第一条指令的首地址。所以,要让 CPU 执行我们放在代码段中的指令,必须要将 CS:IP 指向所定义的代码段中的第一条指令的首地址。比如代码段存放在 123B0H ~ 123B9H 的一组内存单元中,要让这段代码得到执行,可设 CS=123BH、IP=0000H
小结
- 段地址在 8086CPU 的段寄存器中存放。当 8086CPU 要访问内存时,由段寄存器提供内存单元的段地址。8086CPU 有 4 个段寄存器,其中 CS 用来存放指令的段地址
- CS 存放指令的段地址,IP 存放指令的偏移地址。8086 机中,任意时刻,CPU 将 CS:IP 指向的内容当作指令执行。
- 8086CPU 的工作过程:
i. 从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲器
ii. IP 指向下一条指令
iii. 执行指令(转到步骤 i ,重复这个过程) - 8086 提供转移指令修改 CS、IP 的内容