第3章 寄存器(内存访问)
3.1 内存中的字存储
内存以字节为单元,划分为若干个单元。1字节=8比特
在Intel术语规范中:
- 字:16位数据(2字节)
- 双字:32位数据(4字节)
- 四字:64位数据(8字节)
字数据占用两个连续字节,取低地址作为字数据地址。
小端法:从最小的地址开始,先放低位字节数据
大端法:从最小的地址开始,先放高位字节数据
例如:向0号单元写入2049H
8086 CPU 采用小端法存放数据,即高地址内存单元存放字型数据的高位字节,低地址内存单元存放字型数据的低位字节。
3.2 DS 和 [address]
CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在 8086PC 中,内存地址由段地址和偏移地址组成。8086中有一个DS寄存器,通常用来存放要访问数据段的段地址。
DS(Data segment):数据段段寄存器,用于存放数据段的段地址。
在 mov、add、sub等汇编指令中,访问内存单元时,默认情况下,指的是数据段。
[address] 中address表示偏移地址,
例如:
mov ax, [201] ; ax <— (( ds ) × 16 + 201 )
3.3 字的传送
只要在 mov 指令中给出16位寄存器就可以进行16位数据的传送了,即字数据。
3.4 mov 、add、sub 指令
注意事项
- 两个操作数长度要一致
- 关于常数/立即数
1.不能作为目的操作数
2.作为源操作数时,如果最高位是十六进制的a~f 或A ~ F,前面要加0 - 两个内存单元之间不能直接传送数据
- 不能用mov 指令修改CS和IP值
- 关于段寄存器
1.两个段寄存器之间不能直接传送
2.不能把常数送到段寄存器
注意事项
- add指令的操作数不能同时是内存单元
- add指令的操作数不能是段寄存器
- 两个内存单元不能直接使用sub指令相减
- sub指令的操作数不能是段寄存器
3.5 数据段
对于 8086PC 机,可将一组内存单元定义为一个段,将一组长度为N(N<=64)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。
写几条指令,累加数据段中的前3个字型数据。
mov ax, 123BH
mov ds, ax
mov ax, 0
add ax, [0]
add ax, [2]
add ax, [4]
3.6 栈
栈是一个逻辑上的概念,可以将一段内存空间当作栈来使用。
栈的特性:后进先出
两个概念:栈底、栈顶
两个操作:入栈、出栈
一个约定:8086中栈以字为存取单元
栈顶:最后入栈的字数据所对应的地址单元
栈底:固定的一端,栈区最高地址单元的前一个单元
入栈:把数据存入栈
出栈:从栈取出数据
入栈操作分析(push):
①栈顶上移两个单元,即 SP <—— SP-2
②存入数据
出栈操作分析(pop):
①取出字数据
②栈顶下移两个单元,即 SP <——SP+2
说明:栈为空的时候,栈顶指向栈底+2
与栈相关的寄存器SS和SP
SS:栈段段寄存器,用于存放栈段的段地址
SP:栈指针寄存器,用于存放栈顶的偏移地址
SS:SP对应的物理地址是栈顶的物理地址
任意时刻,SS:SP指向栈顶元素。
8086CPU 只记录栈顶,栈空间的大小我们自己管理。
push、pop指令实质上是一种内存传送指令。
注意事项
- 操作对象不能是常数
pop 段寄存器
指令中,段寄存器不能是CS和SS- 栈顶越界
当栈满的时候,再使用push指令入栈;
当栈空的时候,再使用pop指令出栈;
栈应用举例:
- 利用栈“保存现场”
- 利用栈实现数据交换
段是一个逻辑上的概念。编程时,可根据需要指定一段内存空间用作数据段、代码段或是栈段。
- 用作数据段时,要把段地址→DS
- 用作栈段时,要把段地址→SS,栈顶偏移地址 → SP
- 用作代码段时,要把段地址→CS,要取的指令偏移地址→IP。但CS和IP的值不能使用 mov 改变。
检测点3.1
(1)在Debug中,用“d 0:01f” 查看内存,结果如下
0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 88
AX=0,BX=0,写出每条汇编指令执行完后相关寄存器中的值
mov ax,1
mov ds,ax
mov ax,[0000] ;AX=2662H
mov bx,[0001] ;BX=E626H
mov ax,bx ;AX=E626H
mov ax,[0000] ;AX=2662H
mov bx,[0002] ;BX=D6E6H
add ax,bx ;AX=FD48H
add ax,[0004] ;AX=2C14H
mov ax,0 ;AX=0000H
mov al,[0002] ;AX=00E6H
mov bx,0 ;BX=0000H
mov bl,[000C] ;BX=0026H
add al,bl ;AX=000CH
可以使用debug编写指令进行验证
-e 向内存写入数据
-a 编写汇编指令
-t 单步追踪
(2) 内存中的情况如图所示
各寄存器的初始值:cs=2000h,ip=0,ds=1000h,ax=0,bx=0;
①写出CPU执行的指令序列。
②写出CPU执行每条指令后,CS、IP和相关寄存器中的数值。
③再次体会:数据和程序有区别吗?如何确定内存中的信息哪些是数据,哪些是程序?
①
mov ax,6622
jmp 0ff0:0100
mov ax,2000
mov ds,ax
mov ax,[0008]
mov ax,[0002]
②
寄存器\指令 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
CS | 2000 | 1000 | 1000 | 1000 | 1000 | 1000 |
IP | 0003 | 0000 | 0003 | 0005 | 0008 | 000B |
AX | 6622 | 6622 | 2000 | 2000 | C389 | EA66 |
BX | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |
DS | 1000 | 1000 | 1000 | 2000 | 2000 | 2000 |
③数据和程序在计算机中都是以二进制的形式存放的,在区别程序和数据时,关键是看段地址,如果段地址是ds段,说明内存中存放的是数据,如果段地址是cs段,说明该内存中存放的是程序指令。
检测点3.2
补全代码,使其可以将10000H~1000FH中的8个字,逆序复制到20000H ~2000FH中。
(1)
mov ax,1000H
mov ds,ax
mov ax,2000H
mov ss,ax
mov sp,0010H
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
(2)
mov ax,2000H
mov ds,ax
mov ax,1000H
mov ss,ax
mov sp,0000H
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]