检测点 9.3
补全程序,利用 loop 指令实现在内存 2000H 段中查找第一个值为 0 的字节;找到后,将它的偏移地址存储在 DX 寄存器中。
与检测点 9.2 一样,本题存在三个问题:
1. 当指定的 2000h 段中不存在值为 0 的字节时,程序将陷入 s 标号至“loop s”指令之间的死循环。
2. 程序在两种情况下都应该转移至 ok 标号处,这两种情况是:
(1) 当查找到首个字节值为 0 时。
(2) 当 2000h 段中不存在值为 0 的字节,并且已经查找完段中所有字节后(即 (bx)=FFFFh)。
另外,必需在程序未尾,能够通过一定的手段判断出“程序转移至 ok 标号处”这一结果,是基于这两种情况的哪一种。
3. 原题中给出允许添加的指令数量是 1 条,而 1 条指令如何能同时解决上述第 1、2 两个问题。
通常,上述第 3 个问题是无法解决的:无法仅用 1 条指令同时实现肯定“不陷入死循环”和“在上述两种情况下都能转移至 ok 标号处”。
下面列出几种实现本检测点功能的方法:
方法 1(存在可能陷入死循环的有缺陷方法 —— hk9_3er.asm):
说明:仅在题目要求补全代码处添加一条“inc cx”指令,这仅适合在“2000h 段中必定存在字节值 0”条件下执行;但本程序添加了“loop u”循环,以对 2000h 段字节的初始化进行人为操控 —— 将 2000h 段字节初始化为非 0 值,从而测试本程序运行后是否会陷入“loop s”死循环。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
; 初始化 2000h 段内存单元的初值
mov cx,0FFFFh
u: mov byte ptr [bx],0FFh
inc bx
loop u
; loop u 循环无法将指定的数值数据传送到 ds:ffff 内存单元中;因为 16 位的 CX 寄存器只能进行 FFFEh 次的 loop u 循环(从 FFFFh 到 0001h)
; 这可以通过 Debug 运行本程序时,执行下面一行代码前,用 R 命令查看 BX 寄存器存储的值来证明
mov byte ptr [bx],0FFh
mov bx,0FFFDh ; 为了缩短 s 标号至“loop s”指令之间的循环而设置,以证明该循环为死循环;否则,应该将 0 值赋给 bx,以便从 2000h 段的 [0] 开始查看,而不是如此行代码所示的,从 2000h 段 [0FFFDh] 开始查看。
s: mov cl,[bx]
mov ch,0
inc cx
inc bx
loop s
ok: dec bx ; dec 指令的功能和 inc 相反,“dec bx”进行的操作为:(bx)=(bx)-1
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
方法 2(chk9_3wr.asm)
说明:仅在题目要求补全代码处添加一条指令,这适合在“2000h 段中必定存在字节值为 0”条件下执行。
注意,默认情况下在 2000h 段中存在字节的值为 0。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
inc cx
inc bx
loop s
ok: dec bx ; dec 指令的功能和 inc 相反,“dec bx”进行的操作为:(bx)=(bx)-1
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
方法 3(chk9_3cr.asm):
在题目要求补全代码处添加以下指令:
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
说明:
1. 修正了“方法 1(chk9_3er.asm)”程序运行在“2000h 段不存在值为 0 的字节”时,将陷入“loop s”死循环的缺陷。
2. 添加了“loop u”循环,以对 2000h 段字节内存单元进行初始化操作 —— 将 2000h 段字节初始化为非 0 值,从而测试本程序运行后是否能够成功修正“陷入‘loop s’死循环”的缺陷。
3. 最后,当程序跳至 ok 标号处执行完其下面的“mov dx,bx”指令后,即可进行以下判断:
(1) 如果 (bx)=FFFFh,则程序因为查看到 2000h 段的最后一个字节后而无条件转移到 ok 标号,并未对该字节单元存储的值执行“是否为 0”的判别操作,因为不会执行“loop s”指令以判别其“是否为 0”;这时,可通过 AX 寄存器存储的值来确认这一判别:如果 (ax)=0,则说明 2000:[FFFF] 字节单元的值为 0,相反,若 (ax)≠0,则说明 2000:[FFFF] 字节单元的值不为 0,并且 2000h 段中不存在值为 0 的字节单元 —— 如果 2000h 段中存在值为 0 的字节,就根本不会执行到查看 2000:[FFFF] 字节而早就跳至 ok 标号处了。
(2) 如果 (bx)≠FFFFh,则说明 2000:[bx] 字节的值为 0,即值为 0 的字节的偏移地址已被存入 DX 寄存器。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
; 初始化 2000h 段内存单元的初值
mov cx,0FFFFh
u: mov byte ptr [bx],0FFh
inc bx
loop u
; loop u 循环无法将指定的数值数据传送到 ds:ffff 内存单元中;因为 16 位的 CX 寄存器只能进行 FFFEh 次的 loop u 循环(从 FFFFh 到 0001h)
; 这可以通过 Debug 运行本程序时,执行下面一行代码前,用 R 命令查看 BX 寄存器存储的值来证明
mov byte ptr [bx],0FFh
mov bx,0FFFDh ; 为了缩短 s 标号至“loop s”指令之间的循环而设置,以证明该循环为死循环;否则,应该将 0 值赋给 bx,以便从 2000h 段的 [0] 开始查看,而不是如此行代码所示的,从 2000h 段 [0FFFDh] 开始查看。
s: mov cl,[bx]
mov ch,0
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
inc bx
loop s
ok: dec bx ; dec 指令的功能和 inc 相反,“dec bx”进行的操作为:(bx)=(bx)-1
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
方法 4(chk9_3_1):
说明:
1. 在题目要求补全代码处添加以下指令:
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
2. 本程序不对 2000h 段字节内存单元进行初始化操作。
3. 最后,当程序跳至 ok 标号处执行完其下面的“mov dx,bx”指令后,即可进行以下判断:
(1) 如果 (bx)=FFFFh,则程序因为查看到 2000h 段的最后一个字节后而无条件转移到 ok 标号,并未对该字节单元存储的值执行“是否为 0”的判别操作,因为不会执行“loop s”指令以判别其“是否为 0”;这时,可通过 AX 寄存器存储的值来确认这一判别:如果 (ax)=0,则说明 2000:[FFFF] 字节单元的值为 0,相反,若 (ax)≠0,则说明 2000:[FFFF] 字节单元的值不为 0,并且 2000h 段中不存在值为 0 的字节单元 —— 如果 2000h 段中存在值为 0 的字节,就根本不会执行到查看 2000:[FFFF] 字节而早就跳至 ok 标号处了。
(2) 如果 (bx)≠FFFFh,则说明 2000:[bx] 字节的值为 0,即值为 0 的字节的偏移地址已被存入 DX 寄存器。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
inc bx
loop s
ok: dec bx ; dec 指令的功能和 inc 相反,“dec bx”进行的操作为:(bx)=(bx)-1
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
方法 5(chk9_3_2.asm)
说明:
1. 在题目要求补全代码处添加以下指令:
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
2. 添加了“loop u”循环,以对 2000h 段字节内存单元进行初始化操作 —— 将 2000h 段最后一个字节 [FFFFh] 初始化为 0 值,而其他所有字节则初始化为非 0 值,从而测试本程序运行后是否能够成功修正“陷入‘loop s’死循环”的缺陷。
3. 最后,当程序跳至 ok 标号处执行完其下面的“mov dx,bx”指令后,即可进行以下判断:
(1) 如果 (bx)=FFFFh,则程序因为查看到 2000h 段的最后一个字节后而无条件转移到 ok 标号,并未对该字节单元存储的值执行“是否为 0”的判别操作,因为不会执行“loop s”指令以判别其“是否为 0”;这时,可通过 AX 寄存器存储的值来确认这一判别:如果 (ax)=0,则说明 2000:[FFFF] 字节单元的值为 0,相反,若 (ax)≠0,则说明 2000:[FFFF] 字节单元的值不为 0,并且 2000h 段中不存在值为 0 的字节单元 —— 如果 2000h 段中存在值为 0 的字节,就根本不会执行到查看 2000:[FFFF] 字节而早就跳至 ok 标号处了。
(2) 如果 (bx)≠FFFFh,则说明 2000:[bx] 字节的值为 0,即值为 0 的字节的偏移地址已被存入 DX 寄存器。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
; 初始化 2000h 段内存单元的初值
mov cx,0FFFFh
u: mov byte ptr [bx],0FFh
inc bx
loop u
; loop u 循环无法将指定的数值数据传送到 ds:ffff 内存单元中;因为 16 位的 CX 寄存器只能进行 FFFEh 次的 loop u 循环(从 FFFFh 到 0001h)
; 这可以通过 Debug 运行本程序时,执行下面一行代码前,用 R 命令查看 BX 寄存器存储的值来证明
mov byte ptr [bx],0 ; 将 2000:[FFFF] 字节初始化为 0,而 2000h 段中其他的字节则初始化为 FFh。
mov bx,0FFFDh ; 为了缩短 s 标号至“loop s”指令之间的循环而设置,以证明该循环为死循环;否则,应该将 0 值赋给 bx,以便从 2000h 段的 [0] 开始查看,而不是如此行代码所示的,从 2000h 段 [0FFFDh] 开始查看。
s: mov cl,[bx]
mov ch,0
mov ax,cx
mov cx,bx
inc cx
jcxz ok
mov cx,ax
inc cx
inc bx
loop s
ok: dec bx ; dec 指令的功能和 inc 相反,“dec bx”进行的操作为:(bx)=(bx)-1
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start