ICS 与 8086 复习 10:DEBUG 调试与汇编实验
汇编实验的复习重点,是能够预测并验证每一步状态变化:当前执行哪条指令,哪些寄存器会改变,操作数来自哪里,结果写到哪里。只记住“程序最后显示 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
程序的四个检查点值得单独记录。
- ES 与 DS 都初始化为数据段。CMPSB 比较的是 DS:SI 与 ES:DI,不能只设置 DS。
- CLD 把方向标志清零,使每次比较后 SI、DI 向高地址移动。
- 首次执行 REPE CMPSB 只先检查 CX,不依据进入前的旧 ZF;此后每比较一对字节,才按刚产生的 ZF 与剩余 CX 决定是否继续。遇到不等字节即停止,此时 ZF=0。
- 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页环境与建立过程。文档页码可能随排版变化,可按实验或命令标题查找;示例代码按相应实验目标编写。
讨论这篇文章
关于《ICS 与 8086 复习 10:DEBUG 调试与汇编实验》的补充、不同意见或延伸话题,都可以留在这里。
滚动到这里时自动载入留言。