从内存访问的角度了解寄存器
cpu中用16位寄存器来存储一个字. 高8位存放高位字节, 低8位存放低位字节. 由于内存单元是字节单元,一个字需要2个连续的内存单元来存放.
任何2个地址连续的内存单元,N和N+1号单元,可以将它们看成两个内存单元,也可以看成是一个地址为N的字单元中的高位字节单元和低位字节单元
8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址.
比如要读取10000H中的内容
mov bx,1000H
mov ds,bx
mov al,[0]mov,add,sub指令形式:
| 指令形式 | 例子 |
|---|---|
| mov 寄存器,数据 | mov ax,8 |
| mov 寄存器,寄存器 | mov bx,ax |
| mov 寄存器,内存单元 | mov ax,[0] |
| mov 内存单元,寄存器 | mov [0],ax |
| mov 内存单元,段寄存器 | mov [0],ds |
| mov 段寄存器,内存单元 | mov ds,[0] |
| mov 段寄存器,寄存器 | mov ds,ax |
| mov 寄存器,段寄存器 | mov ax,ds |
| add 寄存器,数据 | add ax,8 |
| add 寄存器,寄存器 | add bx,ax |
| add 寄存器,内存单元 | add ax,[0] |
| add 内存单元,寄存器 | add [0],ax |
| sub 寄存器,数据 | sub ax,8 |
| sub 寄存器,寄存器 | sub bx,ax |
| sub 寄存器,内存单元 | sub ax,[0] |
| sub 内存单元,寄存器 | sub [0],ax |
[...]表示一个内存单元,[...]中的0表示内存单元的偏移地址
- 定义数据段: 在编程时,可以根据需要,将一组内存单元(起始地址必须为16的倍数, 长度为N<=64KB)定义为一个段
- 访问数据段: mov,add,sub,jmp等指令
如将123B0H~123B9H的内存单元定义为数据段(起始地址123BH, 长度为10个字节),现在需要累加该数据段前3个单元中的数据
mov ax,123B
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]
8086CPU可以将一段内存当做栈来使用. 8086CPU中入栈和出栈的操作都是以字为单位
- push 入栈: 如
push ax表示将寄存器ax的值送入栈中 - pop 出栈:如
push ax表示从栈顶取出数据送入ax
有如下指令
mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
push cx
pop ax
pop bx
pop cx下图描述其执行过程
注意: 字型数据用2个单元存放, 高地址单元存放高8位, 低地址单元存放低8位
任意时刻, SS:SP指向栈顶元素
push ax执行分为2步(入栈时,栈顶从高地址向低地址方向增长)
SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶- 将ax中的内容送入
SS:SP指向的内存单元处,SS:SP此时指向新栈顶
pop ax的执行过程和push ax相反
- 将
SS:SP指向内存单元处的数据送入ax中 SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶
出栈后, SS:SP指向新的栈顶1000EH, 之前的栈顶1000CH处的数据2266H依然存在, 只是不再栈中. 当再次执行push等入栈指令后, SS:SP移至1000CH, 并在里面写入新的数据将其覆盖
8086CPU不保证对栈的操作不会超界. 8086CPU只知道栈顶在何处(由SS:SP指示),而不知道我们安排的栈空间有多大.
push, pop等栈操作指令, 修改的只是SP. 栈顶的变化范围最大为0~FFFFH
8086CPU的栈操作机制:
- 提供
SS,SP指示栈顶 - 改变
SP后写内存的入栈指令 - 读内存后改变
SP的出栈指令
形式:
| 指令 | 解释 |
|---|---|
| push 寄存器 | 将一个寄存器中的数据入栈 |
| pop 寄存器 | 出栈, 用一个寄存器接收出栈的数据 |
| push 段寄存器 | 将一个段寄存器中的数据入栈 |
| pop 段寄存器 | 出栈, 用一个段寄存器接收出栈的数据 |
| push 内存单元 | 将一个内存字单元处的字入栈(注: 栈操作都是以字为单位) |
| pop 内存单元 | 出栈, 用一个内存单元接收出栈的数据 |
mov ax,1000H
mov ds,ax ;内存单元的段地址要放在ds中
push [0] ;将1000:0处的字压入栈中
pop [2] ;出栈, 出栈的数据送入1000:2处编程:
- 将
10000H~1000FH这段空间当做栈,初始状态栈是空的 - 设置
AX=001AH, BX=001BH - 将AX,BX中的数据入栈
- 然后将AX,BX清零
- 从栈中回复AX,BX原来的内容
mov ax,1000H
mov ss,ax
mov sp,0010H ;初始化栈顶
mov ax,001AH
mov bx,001BH
push ax
push bx ;ax,bx入栈
sub ax,ax ;将ax清零, 也可以使用mov ax,0
;sub ax,ax的机器码为2个字节
;mov ax,0的机器码为3个字节
sub bx,bx
pop bx ;从栈中回复ax,bx原来的数据,当前栈顶的内容是bx
pop ax ;ax中原来的内容001AH在栈顶的下面, 所以要先pop bx,再pop ax
我们可以将一段内存定义为一个段, 用一个段地址指示段, 用偏移地址访问段内的单元.这完全是我们自己的安排
- 数据段
- 用一个段存放数据(ds寄存器)
- 用
mov,add,sub等访问内存单元的指令时,cpu就将数据段中的内容当做数据来访问
- 代码段:
- 用一个段存放代码(cs寄存器)
- 将断种第一条指令的偏移地址放在ip寄存器中,cpu就将执行代码段中的指令
- 栈段:
- 用一个段当做栈(ss寄存器)
- 将栈顶单元的偏移地址放到sp寄存器中,cpu在执行
push,pop指令时将栈段当做栈空间来用
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以都不是. 关键在于cpu中寄存器的设置,即cs,ip,ss,sp,ds的指向



