标签:内存 完成 语言 相减 str pop 数据段 小端 取数
第三章 内存访问
字数据在内存中的存储
1. 内存以字节为单位,划分为若干个单元
2. 字数据的存-取原则:高-高 低-低(小端法)
即:
① 字数据的低位字节存放在低地址内存单元
字数据的高位字节存放在高地址内存单元
② 取低地址内存单元地址作为字数据地址
例1:
字数据124EH的地址是( 1 )
字数据3020H存入内存后地址为4,则4存放( 30H ),3存放( 20H )
例2:
从地址单元1取出一个
(1) 字节数据为: 4EH
(2) 字数据为:124EH
(3) 双字数据为:2000124EH
数据在内存和CPU之间的传送
1. 要在CPU和内存单元之间传送数据,就必须知道内存单元的地址。
2. 执行指令时,默认情况下,8086自动取寄存器DS中的值为内存单元的段地址。
3. 用mov指令从10000H中读取数据
1)10000H用段地址和偏移地址表示为1000:0
2)将1000H放入ds,然后用 mov al,[0]
[…]表示一个内存单元,[…]中的数字表示内存单元的偏移地址,段地址默认放在ds内执行时自动取出
4. DS寄存器(数据段段寄存器,用于存放数据段的「段地址」)
说明:
(1) 将一段内存用作数据段,是编程时的一种安排
(2) 在mov, add, sub等汇编指令中,访问内存单元时,默认情况下,指的是数据段。
mov ax, [1] ;ax? ((ds)) x 16 + 1)
汇编指令mov, add, sub
1. mov形式
注意:
1) 两个操作数长度要一致
2) 关于常数(也叫立即数)
① 不能作为第1个操作数(目的操作数)
② 作第2个操作数(源操作数)时,如果最高位是十六进制的a~f或A~F,前面要加零
3) 两个内存单元之间不能直接传送数据
4) 不能使用mov指令修改CS和IP的值
5) 关于段寄存器
① 两个段寄存器之间不能直接传送;
② 不能把常数送到段寄存器。
错误举例:
1) mov ax,cl
2) ,mov al 300
3) mov 4000H,ax
4) mov ax A400H
5) mov [1],[2]
6) mov ds,cs
7) mov ds,1000H
2. add形式
注意:
1) 操作数是内存单元时,指令中只给出「偏移地址」
2) 默认,「段地址」在ds中
3) add指令的操作数不能同时是内存单元
4) add指令的操作数不能是段寄存器
错误举例
1) add [1],[2]
2) add ds,[2]
3. sub形式
注意:
1) 操作数是内存单元时,指令中只给出「偏移地址」
2) 默认,「段地址」在ds中
3) 两个内存单元不能直接使用sub指令相减
4) sub指令的操作数不能是段寄存器
错误举例:
1)sub [1],[2]
mov,add,sub举例
例1:写指令,计算从123B0H单元开始的前3个字节数据的累加和
mov ax, 123BH
mov ds, ax
mov al, 0
add al, [0]
add al, [1]
add al, [2]
例2:写指令,计算从123B0H单元开始的前3个字数据的累加和
mov ax, 123BH
mov ds, ax
mov ax, 0
add ax, [0]
add ax, [2]
add ax, [4]
例3:写指令,交换从123B0H单元开始的两个字节数据
mov ax, 123BH
mov ds, ax
mov al, [0]
mov bl, [1]
mov [1], al
mov [0], bl
栈
1. 栈是一个逻辑上的概念,可以将一段内存空间当作「栈」来使用
2. 栈的特性:后进先出
3. 8086中栈以字为存取单位
4. 栈顶: 最后入栈的字数据所对应的地址单元
5. 栈底: 固定的一端,栈区最高地址单元的前一个单元
6. 入栈: 把数据存入栈
第1步: 栈顶上移两个单元,即: 栈顶-2 → 栈顶
第2步: 存入数据
7. 出栈: 从栈取出数据
第1步: 取出字数据 → AX
第2步: 栈顶下移两个单元,即: 栈顶+2 → 栈顶
8. 从栈中取出一个字数据给BX
第1步: 取出数据→ BX
第2步: 栈顶下移两个单元,即: 栈顶+2→栈顶
9. 栈为空时,栈顶指向栈底+2
与「栈」相关的寄存器SS和SP
1. SS: 栈段段寄存器,用于存放栈段的「段地址」
2. SP: 栈指针寄存器,用于存放栈顶的偏移地址
3. SS:SP对应的物理地址是栈顶的物理地址
(SS) × 16 + (SP) → 栈顶的物理地址
例子:设将20000H~2FFFFH这段内存当作栈来使用,栈的当前状态如图所示。
分析连续两次出栈操作SS和SP的内容的变化
初始:
(SS) = 2000H
(SP) = FFFCH
第1次出栈:
(SS) = 2000H
(SP) = FFFEH
第2次出栈:
(SS) = 2000H
(SP) = 0000H
「栈」操作指令: push和pop
注意:
1) 在 push 内存单元 和 pop内存单元 中,指令中只需给出「偏移地址」,默认段地址在DS中
2) 对8086CPU而言,push和pop的操作:
入栈和出栈均以字为单元
操作对象不能是常数
pop 段寄存器中,段寄存器不能是CS和SS
3) 利用栈「后入先出」特性,使用push和pop指令可以完成一些特殊处理
4) 以下两种情形会发生「栈顶超界」问题
1.当栈满的时候,再使用push指令入栈
2.当栈空的时候,再使用pop指令出栈
8086CPU不会自动考虑栈顶超界,需要程序员在编程设计时自己考虑。栈区长度不同,栈顶超界的具体情形也不同。
举例:
1.设将10000H~1FFFFH这段内存当作栈来使用
栈的初始状态如图所示。(SS) = 1000H (SP) = 000EH
pop ax ; (ax) = 1234H
SP ← (SP) + 2
(SP) = 0010H
pop ax ; (ax) = ××H
SP ← (SP) + 2
(SP) = 0012H
2. 设将10000H~1000FH这段内存当作栈来使用
栈的初始状态如图所示。(SS) = 1000H (SP) = FFFEH
pop ax ; (ax) = 1234H
SP ← (SP) + 2
(SP) = 0000H
pop ax ; (ax) = ××H
SP ← (SP) + 2
(SP) = 0002H
利用栈“保护现场”
设将10000H~1000FH这段内存当作栈来使用
栈的初始状态为空。(bx)=0010H, (cx)=2010H
mov ax, 1000H
mov ss, ax
mov sp, 0010H
push bx
push cx
… ;修改bx,cx
pop cx
pop bx
代码段执行完后,bx和cx内容未变
利用栈实现数据交换
设将10000H~1000FH这段内存当作栈来使用
栈的初始状态为空。(bx)=0010H, (cx)=2010H
mov ax, 1000H
mov ss, ax
mov sp, 0010H
push bx
push cx
… ;修改bx,cx
pop bx
pop cx
代码段执行完后,bx和cx内容交换
关于「段」的小结
(1)「段」是一个逻辑上的概念。
编程时,可根据需要指定一段内存区用作数据段、代码段或是栈段。
(2) 用作数据段时,要把段地址→DS
用作栈段时,要把段地址→SS,栈顶偏移地址 → SP
用作代码段时,段地址→CS,要取的指令偏移地址→IP。但CS和IP的值不能使用mov改变。
(3) 一段内存可以同时用作代码段、数据段、栈段。
由编程时灵活确定。
(4) 在8086CPU中,每个段的最大长度不能超过64KB。
(因为寄存器是16位的,能表示的地址范围只能是0000H~FFFFH,即0~216-1)
标签:内存 完成 语言 相减 str pop 数据段 小端 取数
原文地址:https://www.cnblogs.com/gares/p/9922508.html