汇编网首页登录博客注册
unixandlinux的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
最新评论
最新留言
好友圈
友情链接

[2023-06-14 11:22] 第9章 检测点 9.2

检测点 9.2

补全程序,利用 jcxz 指令实现在内存 2000H 段中查找第一个值为 0 的字节,找到后将它的偏移地址存储在 DX 寄存器中。

assume cs:code

code segment

start:  mov ax,2000h
        mov ds,ax
        mov bx,0

s:      ________
        ________
        ________
        ________
        jmp short s

ok:  mov dx,bx

     mov ax,4c00h
     int 21h

code ends
end start

本题在两种情况下应该跳出标号 s 与“jmp short s”指令之间的循环:
(1) 当在 2000h 段中找到第 1 个值为 0 的字节内存单元时。
(2) 当 2000h 段中不存在值为 0 的字节内存单元时(此时 (bx)=0FFFFh)。
另外,假设 [0] 内存单元的值为 0,并且程序顺利跳出标号 s 与“jmp short s”指令之间的循环,则无法判断程序是因为找到了 2000h 段中的第一个值为 0 的字节而退出该循环的,还是因为 2000h 段中不存在值为 0 的字节内存单元以致于运行到 (bx)=0FFFFh 后而退出该循环的;即应该能够在程序执行完毕而未返回操作系统前,可以通过某个标志来确认程序是因为上述两种情况中的哪一种情况,导致结束 s 标号与“jmp short s”指令之间的循环而跳至 ok 标号处执行。
本题的困难在于:
(1) 当 2000h 段中不存在值为 0 的字节内存单元时,不要使得程序陷入标号 s 与“jmp short s”指令之间的死循环。
一种会导致陷入这种死循环的有缺陷的答案是:
mov cl,[bx]
and ch,00000000B  ; 或“mov ch,0”,又或“mov ch,cl”
jcxz ok
inc bx
注意,“inc bx”指令必须放在“jcxz ok”指令之后,因为后面的“mov dx,bx”指令需要将指令“inc bx”执行之前的 bx 传送给 dx。
(2) 当程序执行结束后,如果 (dx)=0,则必须能够判断程序跳出标号 s 与“jmp short s”指令之间的循环,是因为 2000h 段中偏移地址为 0 的字节单元就是第一个值为 0 的字节单元,还是因为 2000h 段中不存在值为 0 的字节单元。
(3) 限定补全的程序代码只能是 4 条语句。然而很难仅用 4 条语句就完美实现题目的要求 —— 所谓“完美实现”是指避免上述第 (1)、(2) 两点问题而完成题目任务。

下面列出补全代码不限定只使用 4 条语句的程序完整代码的方法(即补全的代码超过了 4 条语句):

方法 1(存在可能陷入死循环的有缺陷方法):

; 当 2000h 段中不存在值为 0 的内存单元时,本程序将陷入标号 s 至“jmp short s”指令之间的死循环,
; 由此证明必须在“jmp short s”指令前添加下述代码(这样就导致补全代码必然超过 4 条语句):
; mov cx,bx
; jcxz ok
; 另外,为了手工控制 2000h 段中内存单元所存储的数据值,添加了 loop u 循环。还需说明两点:
; 1. 仅当 2000h 段中不存在值为 0 的字节内存单元时才会执行第 2 个“jcxz ok”指令,且这时 (dx)=(bx)=0
; 2. 当 2000h 段中存在值为 0 的字节内存单元时,必定执行第 1 个“jcxz ok”指令;这时若 (dx)=(bx)=0 则无法判断是因为 2000h 段不存在值为 0 的字节内存单元,还是因为 ds:[0] 的值为 0 而执行“jcxz ok”。除非用 Debug 的 D 命令查看 2000:0000 内存单元存储的数据后才可确定是哪种情况。


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 标号至“jmp short s”指令之间的循环而设置,以证明该循环为死循环
s:      mov cl,[bx]
        and ch,00000000B  ; 或“mov ch,0”,又或“mov ch,cl”
        jcxz ok
        inc bx
        ; 如果以下两行代码不写,则当 2000h 段中不存在值为 0 的字节内存单元时,程序将陷入 s 标号与“jmp short s”指令之间的死循环
        ;mov cx,bx
        ;jcxz ok

        jmp short s

        mov ax,0D3h  ; 本行代码是为方便观察跳出 s 标号与“jmp short s”指令之间的循环后的情况而设置

ok:     mov dx,bx  ; 以下两种情况的任意一种都会跳至 ok 标号:(通过修改 loop u 循环中传送给 2000h 段内存单元的值数据后,重新编译、运行本程序即可验证)
; (1) 2000h 段中偏移地址为 0 的字节的值为 0,这时执行第 1 个“jcxz ok”指令。
; (2) 2000h 段中不存在值为 0 的字节,这时执行第 2 个“jcxz ok”指令。
; 这两种情况都会导致 (dx)=0,所以当 (dx)=0 时,将无法判断是上述两种情况中的哪一种。除非用 Debug 的 D 命令查看 2000:0000 单元存储的数据后才可确定是哪种情况。

        mov ax,4c00h
        int 21h

code ends

end start

方法 2:

本程序修正了“方法 1”的缺陷,但仍存在“当 (dx)=0 时无法判断 2000h 段偏移地址为 0 的单元存储的数据值为 0,还是该段不存在值为 0 的单元”缺陷的方法。

; 当 2000h 段中不存在值为 0 的内存单元时,必须在“jmp short s”指令前添加下述两行代码,才能避免陷入 s 标号至“jmp short s”指令之间的死循环:
; mov cx,bx
; jcxz ok
; 另外,为了手工控制 2000h 段中内存单元所存储的数据值,添加 loop u 循环。还需说明两点:
; 1. 仅当 2000h 段中不存在值为 0 的字节内存单元时才会执行第 2 个“jcxz ok”指令,且这时 (dx)=(bx)=0
; 2. 当 2000h 段中存在值为 0 的字节内存单元时,必定执行第 1 个“jcxz ok”指令;这时若 (dx)=(bx)=0,则无法判断是因为 2000h 段不存在值为 0 的字节内存单元,还是因为 ds:[0] 的值为 0 而执行“jcxz ok”。除非用 Debug 的 D 命令查看 2000:0000 内存单元存储的数据后才可确定是哪种情况。


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  ; 设置 2000h 段的所有内存单元存储的值都为 FFh,改为“mov byte ptr [bx],0”,则将 2000h 段所有单元的值改为 0
        inc bx
        loop u
        ; loop u 循环无法将指定的数值数据传送到 ds:ffff 内存单元中;因为 16 位的 CX 寄存器只能进行 FFFEh 次的 loop u 循环(从 FFFFh 到 0001h),这可通过 Debug 运行本程序时,执行下面一行代码前,用 R 命令查看 BX 寄存器存储的值来证明
        mov byte ptr [bx],0FFh  ; 改为“mov byte ptr [bx],0”,则改其值为 0

        mov bx,0FFFDh  ; 为缩短 s 标号至“jmp short s”指令之间的循环而设置,以证明需要添加“jmp short s”指令上面两行代码才可以避免陷入该循环的死循环
s:      mov cl,[bx]
        and ch,00000000B  ; 或“mov ch,0”,又或“mov ch,cl”
        jcxz ok
        inc bx
        ; 如果以下两行代码不写,则当 2000h 段中不存在值为 0 的字节内存单元时,程序将陷入 s 标号与“jmp short s”指令之间的死循环
        mov cx,bx
        jcxz ok

        jmp short s

        mov ax,0D3h  ; 本行代码是为方便观察跳出 s 标号与“jmp short s”指令之间的循环后的情况而设置

ok:     mov dx,bx  ; 以下两种情况的任意一种都会跳至 ok 标号:(通过修改 loop u 循环中传送给 2000h 段内存单元的值数据后,重新编译、运行本程序即可验证)
; (1) 2000h 段中偏移地址为 0 的字节的值为 0,这时执行第 1 个“jcxz ok”指令。
; (2) 2000h 段中不存在值为 0 的字节,这时执行第 2 个“jcxz ok”指令。
; 这两种情况都会导致 (dx)=0,所以当 (dx)=0 时,将无法判断是上述两种情况中的哪一种,除非用 Debug 的 D 命令查看 2000:0000 单元存储的数据后才可确定是哪种情况。

        mov ax,4c00h
        int 21h

code ends

end start

方法 3:

本方法修正了以下两种缺陷:
(1) 当 2000h 段中不存在值为 0 的内存单元时,标号 s 至指令“jmp short s”之间将出现死循环。
(2) 当程序执行完毕时 (dx)=(bx)=0 的情况下,无法判断是因为 2000h 段偏移地址为 0 的内存单元存储的值为 0,还是因为 2000h 段中不存在值为 0 的内存单元,而跳出标号 s 至指令“jmp short s”之间的循环。
存在的缺陷是,未能满足题目要求补全的代码仅能包含 4 条语句 —— 补全的代码超过 4 条语句。

; 为了手工控制 2000h 段中内存单元所存储的数据值,添加了 loop u 循环。另需说明:
; 1. 仅当 2000h 段中不存在值为 0 的字节内存单元时才会执行第 2 个“jcxz ok”指令,并且这时 (ax)=FFFFh,(dx)=(bx)=0。
; 2. 当 2000h 段中存在值为 0 的字节内存单元时,必定执行第 1 个“jcxz ok”指令;这时 (ax)=(bx)=(dx)。
; 由上述 1 和 2 即可判断是因为 2000h 段中不存在值为 0 的字节内存单元而执行“jcxz ok”指令,还是因为 ds:[0] 的值为 0 而执行“jcxz ok”,为此需要在第 1 条“jcxz ok”指令前添加“mov ax,bx”指令。


assume cs:code

code segment

start:  mov ax,2000h
        mov ds,ax
        mov bx,0

        ; 初始化 2000h 段内存单元的初值
        mov cx,0FFFFh
u:      mov byte ptr [bx],0
        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 标号至“jmp short s”指令之间的循环而设置,便于验证 s 标号下的“mov ax,bx”指令的作用
s:      mov cl,[bx]
        and ch,00000000B  ; 或“mov ch,0”,又或“mov ch,cl”
        mov ax,bx  ; 本行代码用于帮助判断:
                                                        ; 当 (dx)=0 时,是因为 2000h 段偏移地址为 0 的内存单元存储的值为 0,还是因为 2000h 段中不存在值为 0 的内存单元,而跳至 ok 标号处执行。
        jcxz ok
        inc bx
        ; 如果以下两行代码不写,则当 2000h 段中不存在值为 0 的字节内存单元时,程序将陷入 s 标号与“jmp short s”指令之间的死循环
        mov cx,bx
        jcxz ok

        jmp short s

ok:     mov dx,bx  ; 以下两种情况的任意一种都会跳至 ok 标号:(通过修改 loop u 循环中传送给 2000h 段内存单元的值数据后,重新编译、运行本程序即可验证)
; (1) 2000h 段中偏移地址为 0 的字节的值为 0,这时执行第 1 个“jcxz ok”指令。
; (2) 2000h 段中不存在值为 0 的字节,这时执行第 2 个“jcxz ok”指令。
这两种情况都会导致 (dx)=0,所以当 (dx)=0 时,需要根据 (ax) 的值来进行判断:
; (1) (ax)=(bx),说明 2000h 段中存在值为 0 的内存单元,因此执行了第 1 个“jcxz ok”指令而跳至 ok 标号处,也就是 2000h 段偏移地址为 0 的内存单元的值为 0,导致跳至 ok 标号处执行。
; (2) (ax)=FFFFh 且 (ax)≠(bx)时,说明 2000h 段中不存在值为 0 的字节,因此执行了第 2 个“jcxz ok”指令而跳至 ok 标号处执行。

        mov ax,4c00h
        int 21h

code ends

end start
评论次数(0)  |  浏览次数(113)  |  类型(汇编作业) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码