第五章 [BX]和loop指令
# 第五章 [BX] 和 loop 指令
1. [bx] 和内存单元的描述
[bx] 表示一个内存单元,该内存单元的段地址位于 ds 中,偏移地址位于 bx 中。 该内存单元的完整地址为: ds*16 + bx。
2. loop
循环指令。指令格式为:loop 标号
该指令分两步执行。
第一步,计算 cx = cx -1
第二步,判断 cx 中的值,不为零则跳转至标号出执行程序,如果为零则向下执行。
3. 我们定义的描述性的符号:“()”
“()” 表示一个内存单元或寄存器的内容。也即是存储器中存储的值。
“()” 中的元素可以有 3 中类型:寄存器名、段寄存器名、内存单元的物理地址(一个 20 位数据)。
4. 约定符号 idata 表示常量
在以后的学习中我们约定 idata 表示一个常量。
# 5.1 [BX]
[bx] 表示一个内存单元。
mov ax, [bx] 代码的含义:将 ds:bx 所指向内存单元的内容放入 ax 寄存器中。即:(ax)=((ds*16)+(bx))
mov [bx], ax 代码的含义:将 ax 中的内容放入 ds:bx 所指向的内存单元中。即:((ds*16)+(bx))=(ax)
# 5.2 Loop 指令
首先 loop 指令的格式是:loop 标号。该指令分两步执行:
第一步, 计算 cx = cx - 1;
第二步,判断 cx 中的值,不为零则跳转至标号处执行程序,如果为零则向下执行。
一般使用 loop 指令实现循环功能。格式如下:
mov cx, n
s: add ax, ax
loop s
2
3
2
3
以上代码会循环执行 n 次。(n >= 0)
# 5.3 在 Debug 中跟踪用 loop 指令实现的循环程序
使用 Debug 调试程序时,有几条经常用到的指令。
T 指令,单步执行指令。
g 指令,跳至断点,从当前 IP 执行至指定 IP 处。"g 0012" 表示程序由当前位置执行至 DS:0012 处。
p 指令,循环执行指令,p 指令用于执行完当前次数。
# 5.4 Debug 和汇编编译器 masm 对指令的不同处理
Debug 和汇编编译器 masm 对形如 “mov ax, [0]” 这类指令的处理是不同的。debug 将 "[0]" 看做是一个内存单元,该内存单元的地址是 ds*6 + 0。而编译器直接将 “[0]” 看做立即数 0。因此有如下约定。
(1)在汇编源程序中,如果指令访问一个内存单元,则在指令中必须用 "[...]" 来表示内存单元,如果在 “[...]” 里用一个常量 idata 直接给出内存单元的偏移地址,就要在 “[]” 的前面显式的给出段地址所在的段寄存器。
(2)如果在 “[]” 里面用寄存器,比如 bx, 间接给出内存单元的偏移地址,则段地址默认在 ds 中。当然,也可以显式的给出段地址所在的段寄存器。
以上两点概括来说就是,如果内存单元的偏移地址使用立即数给出,则必须显式指明其段地址所在的段寄存器。
# 5.5 loop 和 [bx] 的联合应用
通过 loop 和 [bx] 联合应用实现对连续内存单元的操作实例:
...
mov bx, 0
mov cx, 50
s: mov ax, [bx]
inc bx
loop s
...
2
3
4
5
6
7
8
2
3
4
5
6
7
8
以上代码通过循环实现了对内存单元 DS:0000H~DS:0032H 内容的操作。
# 5.6 段前缀
如果内存单元的偏移地址由 bx 给出,如 “mov ax, [bx]”,则段地址默认位于 ds 中。我们也可以在访问内存单元的指令中显式的给出内存单元段地址所在的段寄存器。比如:
(1)mov ax, ds:[bx]
(2)mov ax, cs:[bx]
(3)mov ax, ss:[bx]
(4)mov ax, cs:[bx]
(5)mov ax, ss:[0]
(6)mov ax, cs:[0]
这些出现在访问内存单元的指令中,用于显式的指明内存单元的段地址的 “ds:”、“cs:”、“ss:”、“es:”,在汇编语言中称为段前缀。
# 5.7 一段安全的空间
(1)我们需要直接向一段内存汇总写入内容;
(2)这段内存空间不应当存放系统或其他程序的数据或代码,否则写入操作很可能引发错误;
(3)DOS 方式下,一般情况,0:200~0:2ff 空间中没有系统或其他程序的数据或代码;
(4)以后,我们需要直接向一段内存中写入内容时,就使用 0:200~0:2ff 这段空间。
# 5.8 段前缀的使用
当需要操作的内存空间跨段时,显式的使用段前缀给出内存单元的段地址,可以避免在循环中对 ds 的重复设置。
也即是说一个内存单元的段地址不仅仅可以由 ds 给出,也可以通过 cs、ss、es 给出。