技术

ICS 与 8086 复习 10:DEBUG 调试与汇编实验

ICS 与 8086 汇编复习 · 第 10 篇 系列目录 · 上一篇 · 下一篇

汇编实验的复习重点,是能够预测并验证每一步状态变化:当前执行哪条指令,哪些寄存器会改变,操作数来自哪里,结果写到哪里。只记住“程序最后显示 Match”,不足以解释程序为什么正确。

这批材料采用 DOSBox、DOS DEBUG、MASM 与 LINK,练习的是 8086 实模式 DOS 程序。DOSBox 运行在 Windows 上,并不使其中的 INT 21H 程序成为 Win32 汇编程序。

把四次实验串成一条路线

实验 要练熟的能力 复习时应能回答的问题
寻址与 DEBUG 读寄存器、读写内存、逐条执行 这条指令实际访问哪里?
熟悉指令系统 算术、逻辑、字与字节操作 为什么商、余数或标志会这样变化?
建立运行程序 编写、汇编、连接、调试 错误发生在哪个阶段?
循环程序设计 输入转换、循环与输出 计数、边界和非法输入如何处理?

材料给出的环境中,可把一个实验文件夹映射为 DOSBox 的虚拟盘。例如 mount c d:\Debug 把宿主机的指定目录映射成模拟环境里的 C 盘,随后输入 c: 进入。两个 C 盘不应混为一谈。具体宿主路径应替换为读者自己的实验目录。

DEBUG 最常用的九个命令

命令 功能 常用形式
R 查看或修改寄存器 r、r ax
D 查看内存字节 d ds:100 l10
E 修改内存字节 e ds:200 23 01 25 00
A 输入并汇编指令 a cs:100
U 反汇编机器码 u cs:100
T 单步跟踪 t
P 过程方式执行一步 p
G 运行至断点或结束 g=cs:100 10a
Q 退出 DEBUG q

DEBUG 的立即数和地址默认按十六进制解释,不加 H 后缀。L10 是长度 10H,即 16 字节,而非十进制 10 字节。A 命令进入逐行汇编后,输入空行结束这一轮输入。

T 适合看普通指令逐条改变寄存器;P 可用于跨过子程序调用和软中断。执行 DOS 服务时采用 P,通常比一路跟进系统代码更容易观察自己的程序。

G 的断点地址表示暂停并准备执行该位置的指令;不能把它理解成“已经执行完这个地址的指令”。断点地址必须是正确的指令起始位置。

按字节准备数据,再验证一个求和片段

实验一要求把两个字相加并写回内存。为了避免覆盖正在调试的指令,可把数据放在 DS:0200,代码放在 CS:0100;开始前应确认这两片空间在本次实验中可用且不重合。

e ds:200 23 01 25 00 00 00
a cs:100
mov ax,[0200]
add ax,[0202]
mov [0204],ax

最后一个空行用于结束 A 输入。不要直接无断点运行,让 CPU 越过这个没有退出指令的片段;可设置 IP 并只单步执行这三条指令。

r ip
0100
t
t
t
d ds:200 l6

逐步预期如下:读取第一个字后 AX 为 0123H;加上第二个字 0025H 后 AX 为 0148H;写回后,六个数据字节为 23 01 25 00 48 01。

这里 E 输入的是一个个字节。不能把 0123H 整个当作 E 命令中的单字节值输入,也不能把显示顺序误读为高字节在前。调试时应把“AX 的数值为 0148H”与“内存按地址递增显示 48 01”联系起来。

一个完整的字符串比较程序

下面用实验三的思路写成完整 DOS EXE 示例。它先比较长度,再比较内容,避免把只匹配前缀的字符串误判为相等;也处理了长度为零时不执行 CMPSB 的情况。

.model small
.stack 100h
.data
STR1    db '8086'
LEN1    equ $-STR1
STR2    db '8086'
LEN2    equ $-STR2
MSG_OK  db 'Match',13,10,'$'
MSG_NO  db 'No match',13,10,'$'
.code
start:
    mov ax,@data
    mov ds,ax
    mov es,ax
    mov cx,LEN1
    cmp cx,LEN2
    jne different
    jcxz same
    lea si,STR1
    lea di,STR2
    cld
    repe cmpsb
    jne different
same:
    lea dx,MSG_OK
    jmp show
different:
    lea dx,MSG_NO
show:
    mov ah,09h
    int 21h
    mov ax,4c00h
    int 21h
end start

程序的四个检查点值得单独记录。

  1. ES 与 DS 都初始化为数据段。CMPSB 比较的是 DS:SI 与 ES:DI,不能只设置 DS。
  2. CLD 把方向标志清零,使每次比较后 SI、DI 向高地址移动。
  3. 首次执行 REPE CMPSB 只先检查 CX,不依据进入前的旧 ZF;此后每比较一对字节,才按刚产生的 ZF 与剩余 CX 决定是否继续。遇到不等字节即停止,此时 ZF=0。
  4. DOS 的 09H 功能从 DS:DX 输出,直到遇到 $。这个结束符用于输出消息,与待比较字符串的长度计算是两套规则。

保存为 COMPARE.ASM 后,按材料所用工具链在 DOS 环境中执行 MASM COMPARE;、LINK COMPARE;,再运行 COMPARE。分号用于接受相应工具的默认输出文件选项。示例按DOS十六位环境编写,所列输出为静态推导结果,需在上述工具链中编译和验证。

怎样设计有区分度的测试

不要只测一次相等情况。至少准备:完全相同、等长但中间不同、前缀相同但长度不同三组数据。上面的初始输入应显示 Match;把 STR2 改成 8087,应显示 No match;改成 8086X,应在长度比较后走不同分支。

使用 DEBUG COMPARE.EXE 后,先用 R 与 U 查看实际 CS:IP,不要套用 COM 程序通常从 0100H 开始的假设。单步走过 DS、ES 初始化后,观察相应内存、SI、DI、CX 和 ZF;到 INT 21H 时可用 P。

实验报告可围绕四项证据展开:输入与预期、关键指令执行前后的寄存器、实际结果、边界测试。若程序出错,应写清楚原因,例如“未初始化 ES 导致比较另一个段的数据”,比只写“调试后通过”更有复习价值。

按出错阶段缩小排查范围

汇编阶段出错,先看指令拼写、操作数宽度和地址形式,例如把字变量直接送入 AL,或给两个普通内存操作数写一条 MOV。连接阶段出错,再看模块、符号和段定义;链接器提示没有栈段时,应检查独立 EXE 的栈安排。程序能够启动但结果错误,则重点跟踪 DS、ES、循环次数、分支标志和数据初值。

每次改动后只选一个检查点复核,能建立更清楚的因果关系。若同时改了算法、数据和退出方式,即使程序变得“能跑”,也很难判断真正的错误在哪里。

易错点

  • EXE 与 COM 的装入条件不同,不能把 ORG 100H、INT 20H 或某个固定入口地址不加条件地互相照搬。
  • 有符号除法前要正确构造被除数;字除法使用 DX:AX,不能在已有 32 位乘积时又随意用 CWD 覆盖 DX。
  • 用 LOOP 控制循环时避免在循环体中意外改写 CX 或 CL。
  • 十六进制输入应先验证字符,再更新累计值;A—F 转数字需要得到 10—15,不能只取 ASCII 低四位。
  • DEBUG 文档 O 命令一节的示例把命令字母误写成 I;复习时按“读端口 I、写端口 O”区分即可。本篇实验不需要端口或磁盘扇区写入。

三道自测

题 1。 DEBUG 中 d ds:100 l10 显示多少字节?

答: 16 字节,长度 10 按十六进制解释。

题 2。 比较两个同段字符串,为什么还要设置 ES?

答: CMPSB 的目的地址固定使用 ES:DI。同段只是意味着应把 ES 与 DS 设置为相同段值,不表示硬件自动替你这样设置。

题 3。 REPE CMPSB 后 CX=0 是否必然说明两个字符串相等?

答: 不必然。最后一个字节也可能恰好比较失败;还要看 ZF,并先确认长度处理正确。

对应材料

《汇编语言》上机实验内容.doc:第2页实验计划,第3—4页寻址与 DEBUG,第5页算术实验,第6—7页程序建立与字符串比较,第8—9页循环实验。DEBUG命令详细解释.doc:第1—3页 DOSBox,第5—7页 R、D、E,第10—12页 A、G、U,第14—15页 T、P,第16页 I、O、Q。汇编语言实验课 第一次上课内容.pptx:第2—5页环境与建立过程。文档页码可能随排版变化,可按实验或命令标题查找;示例代码按相应实验目标编写。

系列导航

CONTINUE / PATH

从这里继续

顺着当前内容继续,或者换到另一个板块。

讨论这篇文章

关于《ICS 与 8086 复习 10:DEBUG 调试与汇编实验》的补充、不同意见或延伸话题,都可以留在这里。

滚动到这里时自动载入留言。