内存中字的存储
CPU中,用16位寄存器来存储一个字,高8位存放高位字节,低8位存放低位字节
内存中,一个内存单元存放一个字节,一个字则需要两个地址连续的内存单元来存放。字的低位字节存放在低地址单元中,高位字节存放在高地址单元中

0和1两个内存单元中存放数据4E20H
2和3两个内存单元中存放数据0012H
字单元
存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节
如上图
0地址单元中的字节型数据是20H
0地址字单元中存放的字型数据是4E20H
1地址字单元中存放的字型数据位124EH
由此可知,任何两个地址连续的内存单元,N号单元和N+1号单元,可以将它们看成两个内存单元,也可以看成一个地址为N的字单元中的低位字节单元和高位字节单元
DS和[address]
CPU要读写一个内存单元时,需首先给出这个内存单元的地址。
在8086PC中,内存地址由段地址和偏移地址组成
8086CPU中,DS寄存器用于存放要访问的数据的段地址
例:读取10000H内存单元的内容至
al中1
2
3mov bx,1000H
mov ds,bx
mov al,[0]1
2
3mov al,[0]
格式:mov 寄存器名,内存单元地址[...]表示一个内存单元,[...]中的0表示内存单元的偏移地址在读取内存的指令执行时,8086
CPU将自动取DS中的数据为内存单元的段地址,结合[...]中的偏移地址形成内存物理地址,即可将内存单元中的数据读取出来存到al中8086
CPU不支持将数据直接送入段寄存器的操作,只可用一个寄存器进行中转,即先将段地址送入通用寄存器,再由通用寄存器送入段寄存器例:将
al中的数据送入内存单元10000H中1
2
3mov bx,1000H
mov ds,bx
mov [0],al1
2
3mov [0],al
格式:mov 内存单元地址,寄存器名
字的传送
8086CPU是16位结构,有16根数据线,可一次性传送16位的数据,即一个字


MOV,ADD,SUB指令
MOV指令
1 | mov 寄存器,数据 mov ax,8 |
1 | mov 段寄存器,内存单元 |

ADD指令
1 | add 寄存器,数据 add ax,8 |
SUB指令
减法指令
sub ax,9含义:用ax中的值减去9后保存到ax中
1 | sub 寄存器,数据 sub ax,9 |
数据段
可以将一组长度为N(N<=64KB),地址连续,起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段
定义数据段

操作数据段
1 | mov ax,123BH |


栈
具有特殊访问方式的存储空间
基本操作:入栈,出栈
操作规则:LIFO(后进先出)
CPU提供的栈机制
8086CPU提供相关的指令来以栈的方式访问内存空间,即可以将一段内存当作栈来使用
1 | push ;入栈 |
8086CPU的入栈与出栈操作以字为单位进行
CPU如何知道栈顶的位置
8086CPU中,有两个寄存器,段寄存器SS和寄存器SP
SS存放栈顶的段地址
SP存放栈顶的偏移地址
任意时刻,SS:SP指向栈顶元素
push指令和pop指令执行时,CPU从SS和SP中得到栈顶地址
不可直接向段寄存器SS送入数据,需使用通用寄存器中转
PUSH ax指令
SP=SP-2,SS:SP指向当前栈顶上方内存单元,此单元为新的栈顶将ax中的内容送入
SS:SP指向的内存单元处,SS:SP此时指向新的栈顶

8086CPU中,入栈时,栈顶从高地址向低地址方向增长
POP ax指令
将
SS:SP指向的内存单元处的数据送入ax中SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

当栈顶数据执行了出栈操作,此数据并未在栈中删除,但其已经不存在于栈中了,因栈顶的地址是由SS:SP确定的,当其他数据执行入栈操作时,可覆盖已出栈的数据
栈空

任意时刻,SS:SP指向栈顶元素,当栈为空时,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向栈的最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2
栈顶超界问题
栈满超界

栈空超界

8086CPU无法提供任何机制判断对栈的操作是否超界。8086CPU只考虑当前的情况:当前的栈顶在何处、当前要执行的指令是哪一条。
所以只能靠程序员编程时注意出栈,入栈的栈的超界问题。
push、pop指令
push和pop指令可以在寄存器和内存之间传送数据
格式:
1 | push 寄存器 ;寄存器数据入栈 |
push指令与pop指令实质上是一种内存传送指令
栈段
将长度为N(N<=64KB)的一组地址连续,起始地址为16的倍数的内存单元,当作栈空间来使用,从而定义了一个栈段
将一段内存当作栈段,是程序员行为,CPU不会识别栈段,想要栈操作指令可以访问自定义的栈段,需将SS:SP指向自定义栈段
用机器指令和汇编指令编程
Debug的使用
D命令
d 段地址:偏移地址语句查看指定内存单元的内容
d 段寄存器:偏移地址,以段寄存器中的数据为段地址SA,列出从SA:偏移地址开始的内存区间中的数据
例:
-
1
2
3
4
5-r ds
:1000
-d ds:0
查看从1000:0开始的内存区间中的内容
-
1
2
3
4
5-r ds
:1000
-d ds:10 18
查看1000:10-1000:18中的内容
-
1
2
3-d cs:0
查看当前代码段中的指令代码
-
1
2
3-d ss:0
查看当前栈段中的内容
在E、A、U命令中使用段寄存器
同D命令相同,使用段寄存器表示内存单元的段地址
例:
-
1
2
3
4
5-r ds
:1000
-e ds:0 11 22 33 44 55 66
在从1000:0开始的内存区间中写入数据
-
1
2
3-u cs:0
以汇编指令的形式,显示当前代码段中的代码
-
1
2
3
4
5-r ds
:1000
-a ds:0
以汇编指令的形式,向1000:0开始的内存单元中写入指令
下一条指令执行了吗?
在debug中,用A命令写一段程序
1 | mov ax,2000 |

当使用T命令进行单步运行时,mov sp,10未执行,但是寄存器sp的值已经修改,说明mov sp,10在mov ss,ax之后紧接着执行了
结论:Debug的T命令在执行修改寄存器SS的指令时,下一条指令也紧接着执行了,这属于中断机制