简介:这份文档是沈美明、温冬婵《IBM-PC汇编语言程序设计》教材的习题参考答案,面向正在学习80x86汇编语言、需要核对课后练习的学习者,尤其适合备考、自学与课堂复习场景。压缩包内只有1个doc文件,约524KB,按教材章节顺序整理答案,便于逐章对照查阅,已有115人学习。答案覆盖数制转换(十进制、二进制、十六进制互转)、8位补码表示与加减运算及CF/OF标志判断、AND/OR/NOT/XOR等位运算、ASCII码与字符串编码、存储器物理地址计算等核心知识点。每道题给出完整运算过程与结果,如十六进制运算的十进制校核、补码运算的溢出标志分析、字符串ASCII码逐字符列出;读者可据此理解解题思路、验证自己的计算结果,并借此梳理数据表示与运算规则的主线,夯实编写汇编程序所需的基础。
1. 16 位汇编的复习总图:一条从数到指令的主线
汇编语言程序设计的复习,最怕一上来就背助记符,背到寻址方式就断了线。其实这门课的骨架只有一条链:数在机器里长什么样(进制、补码、ASCII)→ 数存在哪里(寄存器、分段内存、堆栈)→ 程序怎么找到它(七种寻址方式与有效地址)→ 找到之后怎么算(算术、逻辑、移位指令与标志位)→ 成批数据怎么搬(串操作与转移指令)。手头这份经典 16 位汇编教材的习题参考答案,章节顺序恰好压在这条链上:第一章全在讲数的表示,第二章讲存储器与寄存器,第三章把寻址方式和指令系统一次摊开。它适合正在系统学 8086 实模式汇编的人当知识地图,也适合考前按模块查漏补缺的人当对照表用,答案本身不是重点,答案背后的推导路径才是。
2. 数制与编码:进制转换、补码与 ASCII 的复习重点
2.1 进制转换:降幂法与除法的分工
十进制转二进制有两条路,考场上用哪条取决于数的大小和你的熟练度。降幂法是先找不超过该数的最大 2 的幂,写 1,再用余数继续往下凑,369 就凑成 2^8+2^6+2^5+2^4+2^0,得到 1 0111 0001B,再四位一组换成 171H。除法是除 2 取余、倒序读,优点是过程机械、不容易漏位,缺点是位数一多容易写乱。两种方法互为校验,做完整套题的人基本都会形成“降幂法写、除法验”的习惯。
转十六进制同理,只是把除 2 换成除 16。而二进制与十六进制之间的互转几乎是送分题:从右往左四位一组,左边不足四位补零,一组对应一个十六进制位;反过来一位十六进制拆成四位二进制。真正容易出错的是十六进制四则运算,因为它按 16 进位和借位,不是按 10。比如 3A+B7H,个位 A+7=11H 写 1 进 1,高位 3+B+1=F,结果是 F1H;ABCD-FEH 要连续借位,最终落到 AACFH。做完用十进制校核一遍,F1H=241、12E3H=4835、AACFH=43727、35325H=217893,四个数对得上,说明进位借位没串。
| 十进制 | 二进制 | 十六进制 | 记忆点 |
|---|---|---|---|
| 369 | 1 0111 0001 | 171H | 三个非零段拼起来 |
| 10000 | 10 0111 0001 0000 | 2710H | 拆成 2、7、1、0 四位 |
| 4095 | 1111 1111 1111 | FFFH | 2^12-1,全 1 |
| 32767 | 0111 1111 1111 1111 | 7FFFH | 16 位有符号数上界,符号位为 0 |
这几道题不是随便挑的数:4095 和 32767 分别是 2^12-1 和 2^15-1,写成二进制全是 1,正好用来记住“全 1 对应 2 的幂减一”这个结论;10000 则是练拆位,练的是把一个十进制数快速切成十六进制四位一组的感觉。想省事的话,写个几行脚本做校核比自己反复验算快得多:
# 只做校核:把手工算出的结果和机器结果对照,不代替手算过程 nums = [369, 10000, 4095, 32767] for n in nums: # bin/hex 自带 0b、0x 前缀,比对时要先去掉 print(n, bin(n)[2:], hex(n)[2:].upper())参数说明很简单:nums换成你自己出的题,[2:]是切掉前缀,.upper()是为了和教材里大写十六进制的写法对齐。注意 32767 的二进制输出是 15 个 1,要补成 16 位才是完整的 7FFFH,这一步补零在考试里经常被忘掉。
2.2 补码与无符号数:一个字节的两副面孔
8 位二进制数有两副面孔:当无符号数看是 0~255,当补码看是 -128~127。求一个负数的补码,操作是“按位取反再加一”,85 是 55H,取反得 AAH,加一得 ABH,所以 -85 的 8 位补码就是 ABH。这个动作在后面的取负指令 NEG 里会再出现一次,本质完全一样。
第一章那道六小问的加减题,价值不在结果,而在 CF 和 OF 两个标志的判定。CF 看的是最高位有没有往外进位或借位,属于无符号数的视角;OF 看的是带符号数有没有溢出,判定口诀是“同号相加得异号即溢出”,或者更机械一点,看符号位的进位和次高位的进位是否相同,不同就是溢出。
| 算式 | 补码运算过程 | 结果 | CF | OF |
|---|---|---|---|---|
| (-85)+76 | ABH+4CH | F7H | 0 | 0 |
| 85+(-76) | 55H+B4H | 09H | 1 | 0 |
| 85-76 | 55H+0B4H | 09H | 0 | 0 |
| 85-(-76) | 55H+4CH | A1H | 0 | 1 |
| (-85)-76 | ABH+0B4H | 5FH | 0 | 1 |
| (-85)-(-76) | ABH+4CH | F7H | 0 | 0 |
看第二行最典型:55H+B4H 最高位明显往前进了位,所以 CF=1,但参与运算的两个数符号位一个是 0 一个是 1,属于异号相加,结果符号位是 0,没有变号,所以 OF=0。再看第四行:55H 加 4CH,两个正数加出一个符号位为 1 的结果 A1H,CF=0 但 OF=1,这就是带符号溢出而进位没发生的情况。很多人一看到 CF=1 就写溢出,一看到 OF=1 就说进位,这是这套题最高频的失分点。
同一个字节换个解读方式,含义完全变了:D8H 当补码是 -40,当无符号是 216;FFH 当补码是 -1,当无符号是 255。梳理下来会发现,题目里“看作带符号数或无符号数”这句话不是客套,它决定了你后面该看 CF 还是看 OF。另外要留意位数扩展,8 位的 -85 送进 16 位寄存器时不能高位补零,要符号扩展成 FFABH,指令层面就是 CBW(字节扩展到字)和 CWD(字扩展到双字),这条在后面做双字运算时是前置条件。
2.3 ASCII 码:字符与数值的双重身份
ASCII 那几道题练的是“同一个字节,当数字是多少、当字符是什么”。4FH 当数是 79,当字符是 O;2BH 是 43 和加号;73H 是 115 和小写 s;59H 是 89 和大写 Y。判断方法很直接:可打印字符集中在 20H~7EH,20H 是空格,30H~39H 是数字 0~9,41H~5AH 是大写字母,61H~7AH 是小写字母。
字符串的题本质是把每个字符逐个查表写出来。那道 “For example,This is a number 369” 的答案就是逐字符展开的字节序列,F 是 46H,o 是 6FH,空格是 20H,逗号是 2CH,直到末尾的 33H、36H、39H、32H 对应数字 3、6、9、2。写的时候按行对着抄,别漏掉空格,空格也是要占一个字节的。
有几个换算关系值得单独记:数字字符和它的数值之间差 30H,字符 '7' 是 37H,减 30H 才得数值 7;大写和小写之间差 20H,'a' 减 20H 就是 'A';回车是 0DH、换行是 0AH,题目里给的顺序照抄即可,别自己调换。这类题最容易忽略的一点是,字符串末尾往往还带控制字符,答案里多出来的 0AH、0DH 不是笔误,是行结束符,抄答案时漏掉就会和标准答案对不上。
提示:ASCII 题丢分大多不是不会查表,而是把字符当成数字直接算。看到 '9' 就写 9,看到空格就跳过,这两类错误占了绝大多数。
3. 存储器与寄存器:物理地址、小端存放和堆栈的三条主线
3.1 寄存器清单与隐含用途
寄存器这块不能只背名字,要按“谁专门干哪件事”来记。通用寄存器 AX、BX、CX、DX 各自有隐含分工:AX 是累加器,乘除法默认用它;DX 在乘除法里存高位、在间接寻址的 I/O 端口号里也靠它;CX 是循环计数,串操作里还兼作重复次数;BX 常作基址寄存器。指针和变址寄存器里,SP 指向栈顶,BP 作堆栈段内的基址,SI 是源变址、DI 是目的变址,串操作默认就是 DS:SI 到 ES:DI 这一对。
| 寄存器 | 宽度 | 常规用途 | 隐含用途 |
|---|---|---|---|
| AX | 16 位(可拆 AH/AL) | 通用数据 | 乘除、I/O 数据传送 |
| BX | 16 位(可拆 BH/BL) | 通用、基址 | 查表、间接寻址 |
| CX | 16 位(可拆 CH/CL) | 计数 | 循环、串操作重复、移位次数 |
| DX | 16 位(可拆 DH/DL) | 通用数据 | 乘除高位、端口号 |
| SP | 16 位 | 栈顶偏移 | PUSH/POP 自动加减 |
| BP | 16 位 | 堆栈段基址 | 默认段为 SS |
| SI / DI | 16 位 | 源 / 目的变址 | 串操作的默认指针 |
| CS / DS / SS / ES | 16 位 | 代码 / 数据 / 堆栈 / 附加段基址 | 决定默认段 |
| IP | 16 位 | 指令指针 | 与 CS 组成取指地址 |
“哪些寄存器可以用来指示存储器地址”这类题,答案就是 BX、BP、SI、DI 四个,加上堆栈操作时的 SP,再加上 386 以后机型里的 EAX 等扩展寄存器。记忆的抓手是:能在方括号里出现的,就是能参与寻址的。段寄存器和 IP 不直接放进方括号算偏移,它们负责提供段基址和取指位置。
3.2 物理地址:段地址左移四位再加偏移
实模式下所有地址计算都绕不开一个公式:物理地址 = 段地址 × 10H + 偏移地址。乘 10H 就是左移四位,段地址相当于先放大 16 倍再和偏移相加。3017:000A 算出来是 3017AH,3015:002A 和 3010:007A 算出来也是 3017AH,三组逻辑地址对应同一个物理单元,这就是“逻辑地址不唯一”的经典例子。
程序入口那道题同理:CS=0A7F0H、IP=2B40H,0A7F0H×10H=0A7F00H,加 2B40H 得 0AAA40H,就是第一条指令的物理地址。这类题只要记住“段左移四位再加偏移”,基本不会错,真正容易错的是位数没对齐就相加,比如把 0A7F0H 直接加 2B40H,答案会差一个数量级。
段本身的限制也要记清楚:实模式下每一段最多 64KB,也就是 10000H 个字节,段起始地址必须能被 16 整除,这就是为什么段地址末尾总是 0。段与段之间可以重叠,代码段、数据段、堆栈段、附加段在内存里排布时并不要求连续,题目里画的那张分段示意图,本质上就是把四个段寄存器指向的位置按比例标出来。
3.3 小端存放:字在内存里怎么排
16 位字放进内存是按小端顺序:低字节放低地址,高字节放高地址。1EE5H 存在 000B0H 单元,就是 B0 单元放 E5H、B1 单元放 1EH;2A3CH 存在 000B3H 单元,就是 B3 放 3CH、B4 放 2AH,中间的 000B2H 空着不参与。
读存储单元那道题是这条规则的反向应用。已知 30020H=12H、30021H=34H、30022H=ABH、30023H=CDH、30024H=EFH,问 30022H 字节单元和 30024H 字节单元的内容,答案直接就是 ABH 和 EFH,因为字节单元只取一个地址。问 30021H 字单元,要取 30021H 和 30022H 两个字节,按小端拼回去,低地址的 34H 是低字节,高地址的 ABH 是高字节,结果是 AB34H;问 30022H 字单元,取 ABH 和 CDH,拼成 CDABH。
| 查询对象 | 涉及单元 | 拼接方式 | 结果 |
|---|---|---|---|
| 30022H 字节 | 30022H | 单字节直取 | ABH |
| 30024H 字节 | 30024H | 单字节直取 | EFH |
| 30021H 字 | 30021H、30022H | 低地址作低字节 | AB34H |
| 30022H 字 | 30022H、30023H | 低地址作低字节 | CDABH |
这类题的失分几乎全在拼反:把 ABH 当低字节写成 ABCD 之类的顺序。养成习惯,先在草稿上标出两个地址的高低,再写结果,比心算稳。
3.4 堆栈:SS:SP 的减与加
堆栈的规则可以用两句话概括:进栈先减 SP 再存数,出栈先取数再加 SP,并且高字节总是存在高地址。物理地址由 SS 和 SP 组合出来,算法和上面完全一样。
SS=0FFA0H、SP=00B0H 时,第一次 PUSH 8057H:SP 先减 2 变成 00AEH,物理地址 = 0FFA0H×10H + 00AEH = 0FFAAEH,57H 存在 FFAAEH,80H 存在 FFAAFH。第二次 PUSH 0F79H:SP 减到 00ACH,79H 存 FFAACH,0FH 存 FFAADH。再执行一次 POP:先取出 FFAACH 和 FFAADH 的两个字节拼成 0F79H,然后 SP 加 2 回到 00AEH。
| 操作 | SP | 涉及的物理单元 | 内容 |
|---|---|---|---|
| 初始 | 00B0H | — | — |
| PUSH 8057H | 00AEH | FFAAEH / FFAAFH | 57H / 80H |
| PUSH 0F79H | 00ACH | FFAACH / FFAADH | 79H / 0FH |
| POP | 00AEH | 取 FFAACH、FFAADH | 弹出 0F79H |
画这张表比画示意图快,考试时在草稿上列三列,SP 变化和内容一一对应,基本不会错。要提醒自己的是,POP 之后内存里的内容并没有被清掉,只是 SP 回去了,那块空间变成“已释放”,这一点在答“堆栈内容变化”类题目时要写清楚,别顺手把单元内容写成 0。
4. 寻址方式与指令书写:有效地址、段约定与转移目标
4.1 七种寻址方式:EA 怎么算
寻址方式的题看似花样多,实际只考一件事:有效地址 EA 由哪几部分相加而成。立即寻址的操作数就在指令里,没有 EA;寄存器寻址的操作数在寄存器里,也没有 EA;剩下的五种都和存储器有关,区别只在于参与相加的成员不同。
| 寻址方式 | 书写形式 | EA 的组成 |
|---|---|---|
| 立即寻址 | MOV AX, 1200H | 无 EA,操作数在指令中 |
| 寄存器寻址 | MOV AX, BX | 无 EA,操作数为 BX 内容 |
| 直接寻址 | MOV AX, [1200H] | EA = 位移量 |
| 寄存器间接 | MOV AX, [BX] | EA = BX |
| 寄存器相对 | MOV AX, 1100[BX] | EA = BX + 位移量 |
| 基址变址 | MOV AX, [BX][SI] | EA = BX + SI |
| 相对基址变址 | MOV AX, 1100[BX][SI] | EA = BX + SI + 位移量 |
那组 BX=637DH、SI=2A9BH、D=7237H 的题就是逐项套表:直接寻址 EA=7237H;[BX] 是 637DH;[BX+D] 是 637DH+7237H=0D5B4H;[BX+SI] 是 8E18H;[BX+SI+D] 算出来是 1004FH。最后这个要特别注意,1004FH 超过了 64KB 的段边界,最高位的进位丢失,EA 只保留低 16 位,结果写成 004FH。这一步几乎每套题都会埋一个,算完看到五位十六进制数,就该条件反射地问自己要不要截断。
4.2 段约定与超越:默认段是怎么定的
算出 EA 只是第一步,还要确定用哪个段寄存器,物理地址才算得出来。默认规则是:取指令用 CS:IP,堆栈操作和 BP 参与的寻址用 SS,串操作的源用 DS:SI、目的用 ES:DI,其余情况一律用 DS。想改默认段,就在指令里写段超越前缀,比如 ES:[BX]。
那组给了 DS=2000H、ES=2100H、SS=1500H、SI=00A0H、BX=0100H、BP=0010H、VAL=0050H 的十二小问,就是把这套规则完整走一遍:
| 指令 | 寻址方式 | 物理地址 |
|---|---|---|
| MOV AX, 0ABH | 立即 | 无 |
| MOV AX, BX | 寄存器 | 无(操作数 0100H) |
| MOV AX, [100H] | 直接 | 20100H |
| MOV AX, VAL | 直接 | 20050H |
| MOV AX, [BX] | 寄存器间接 | 20100H |
| MOV AX, ES:[BX] | 段超越的寄存器间接 | 21100H |
| MOV AX, [BP] | 寄存器间接(默认 SS) | 15010H |
| MOV AX, [SI] | 寄存器间接 | 200A0H |
| MOV AX, [BX+10] | 寄存器相对 | 20110H |
| MOV AX, VAL[BX] | 寄存器相对 | 20150H |
| MOV AX, [BX][SI] | 基址变址 | 201A0H |
| MOV AX, VAL[BX][SI] | 相对基址变址 | 201F0H |
这张表里最值得盯的是 BP 那一行,很多人顺手就按 DS 算成 20010H,正确结果是 SS×10H+BP=15010H。这说明判断默认段不能只看指令长什么样,要先看方括号里出现了哪个寄存器。
4.3 从需求反推指令:OFFSET、PTR 与 LEA
“把首地址为 BLOCK 的字数组的第 6 个字送到 DX”这类题,考的是同一种访问用不同寻址方式怎么写。字数组每个元素占 2 个字节,第 6 个元素的偏移是 (6-1)×2=10。
; 写法一:寄存器间接寻址,先算出元素地址再取值 MOV BX, OFFSET BLOCK ADD BX, (6-1)*2 MOV DX, [BX] ; 写法二:寄存器相对寻址,位移量直接写进指令 MOV BX, OFFSET BLOCK MOV DX, BLOCK[BX] ; 等价于 MOV DX, [BX+10] ; 写法三:基址变址,两个寄存器分工 MOV BX, OFFSET BLOCK MOV SI, (6-1)*2 MOV DX, [BX][SI]三段的差别在“地址算在谁身上”:第一种把偏移加进了 BX,第二种把偏移留在指令的位移量字段里,第三种拆给两个寄存器。参数上要盯住OFFSET取的是偏移地址而不是单元内容,(6-1)*2里的减一是因为数组下标从 0 起。
同类的还有 MOV 和 LEA 的区别:MOV AX, TABLE 取的是 TABLE 单元里的内容,答案是 1234H;LEA AX, TABLE 取的是 TABLE 的偏移地址,答案是 0032H。前者是取值,后者是取地址,一个字母之差,答案完全不同。另外像 ADD WORD PTR [0524H], 2A59H 这种指令,必须用 WORD PTR 说明操作数长度,否则汇编器不知道按字节还是按字处理;两个内存单元之间也不能直接 MOV,必须借一个寄存器中转。
4.4 转移指令:位移量的符号与目标地址
短转移的公式是:目标地址 = 转移指令的下一条指令地址 + 位移量。0624H 处的两字节 JMP SHORT 指令,下一条指令地址是 0626H,位移量 27H 时目标为 064DH,6BH 时目标为 0691H,这两条都是往前跳。
第三个小问的位移量是 C6H,这时要先把 C6H 当补码解读:C6H 的最高位是 1,是负数,取反加一得 3AH,所以它代表 -3AH。0626H-3AH=05ECH,是往回跳。同一个字节,当成无符号数是 198,当成补码是 -58,方向完全相反,这类题错一次就会记一辈子。
段内转移的另外两种形式也要分清:JMP NEAR PTR 5119H 是段内直接寻址,IP 直接置成 5119H,然后加上指令长度 3 字节得到 7CDCH,物理地址按 CS=0200H 算是 09CDCH;JMP WORD PTR [BX] 是段内间接,新的 IP 从内存里取,DS=212AH、BX=1200H,取出的 0600H 就是新 IP;JMP D[BX] 则要先加上位移量 5119H 再取,结果是 098AH,物理地址 0298AH。
5. 易错点排查:标志位、进位链与串操作里最容易翻车的五处
5.1 易错点一:CF 和 OF 混着用
易漏点:算完加减法,CF 和 OF 随手填一个,或者两个填成一样。第二章那道六小问里,85+(-76) 的 CF=1、OF=0,85-(-76) 的 CF=0、OF=1,两个标志正好错开,是最典型的一组对照。
为什么漏:教材讲补码时把两个标志放在一起讲,很多人只记住了“溢出”这个词,没分清 CF 是无符号数的进位/借位,OF 是带符号数的溢出。再加上两条判定规则都需要看最高位和次高位,考试时一赶时间就混。
怎么补:把判定拆成两个独立问题分别回答。先问“当成无符号数,最高位往外进位或借位了吗”,有就 CF=1;再问“当成带符号数,两个同号数加出了异号结果吗”,是就 OF=1。减法统一转成加补码再判,别直接用减法的直觉。练习题里凡是给了“带符号/无符号”字样的,先把这个定语圈出来再动笔。
5.2 易错点二:多字节加减漏掉进位链
易漏点:双字相加时,低 16 位算完有进位,高位却还是用 ADD 而不是 ADC,进位直接丢掉。两个双字相乘要累加四次部分积,中间的进位更是一层套一层,漏一次结果就全错。
为什么漏:单字运算做多了会形成肌肉记忆,看到 ADD 就写,忘了多字节运算的核心是“低位管低位,高位带着进位一起算”。而且 ADC 和 ADD 只差一个字母,抄答案时很容易看漏。
怎么补:写多字节加减时先把进位链画出来,低位用 ADD,高位一律用 ADC;减法低位用 SUB,高位用 SBB。双字求补也有固定套路,两种写法都对:一种是 NOT DX、NOT AX、ADD AX,1、ADC DX,0,另一种是 NEG DX、NEG AX、SBB DX,0。
; 双字求补:对 DX:AX 中的 32 位数取负 NOT DX ; 高位取反 NOT AX ; 低位取反 ADD AX, 1 ; 低位加一,可能产生进位 ADC DX, 0 ; 高位把低位来的进位加上,不能写成 ADD这段的关键在最后一行:如果写成 ADD DX,0,低位产生的进位就丢了,结果是错的。判断自己有没有写对,可以拿一个低位为 0 的数试一遍,比如 0001:0000 求补应该得到 FFFF:0000,进位链断掉就会算成 FFFF:0001。
5.3 易错点三:移位指令选错类型
易漏点:带符号数除以 2 用了 SHR,负数一移就变成大正数;乘 2 用 SHL 没问题,但除 2 该用 SAR 还是 SHR 常常搞混。
为什么漏:SHL 和 SAL 功能完全一样,都是左移补 0,所以左移时选哪个都对,容易让人误以为右移也一样。实际上右移分三种:SHR 逻辑右移高位补 0,SAR 算术右移高位补符号位,ROR/RCR 是循环移位,语义完全不同。
怎么补:记住一条对应关系,带符号数乘 2 用 SAL,带符号数除 2 用 SAR,无符号数除 2 才用 SHR。拿 -49 试一下:补码是 CFH,SAR 一位得 E7H,即 -25,是向下取整;如果误用 SHR,得到 67H 即 103,从负数变成正数,一眼就能看出错。另外多位移位要用 CL 存次数,比如 MOV CL,7 再 SHR BX,CL,不能直接把 7 写进指令。
5.4 易错点四:串操作的方向标志与前缀
易漏点:从右往左传送字符串时忘了先 STD 并把 SI、DI 指到末尾;用 REPNE SCASB 找字符时忘了先把 AL 设成要找的字符;找最后一个 '-' 时没有把指针挪到末尾就往下扫。
为什么漏:串操作指令本身很短,一两个助记符就写完了,真正决定行为的是前面几条准备指令和方向标志,而这些准备动作在答案里往往只占一两行,抄的时候最容易省略。
怎么补:把串操作拆成固定的四步准备:设方向(CLD 递增 / STD 递减)、设 DS:SI 源、设 ES:DI 目的、设 CX 次数。从右往左搬时,SI 和 DI 都要先加上“长度减一”再开始,因为 STD 之后每执行一次就自动减。查最后一个 '-' 的写法是先 MOV CX,9、STD、LEADI, STUDENT_ADDR+8,再 REPNE SCASB,扫到后 DI 还要加一才指向匹配位置。这几步写成模板背下来,比每次现推省时间。
5.5 易错点五:MOV 与 LEA 不分、内存直传
易漏点:把 MOV AX, TABLE 和 LEA AX, TABLE 当成一回事;想当然地写 MOV [0524H], [BX] 这种内存到内存的指令;忘记 WORD PTR 导致操作数长度不明确。
为什么漏:MOV 太熟了,熟到不看第二个操作数是地址还是内容;LEA 平时用得少,只在取数组首地址时出现,印象淡。内存直传则在高级语言思维里天经地义,落到汇编就是非法指令。
怎么补:给 MOV 和 LEA 各配一句口诀,MOV 取内容,LEA 取地址。判断时可以看对方是不是变量名:MOV AX, VAL 拿的是 VAL 里的值,LEA AX, VAL 拿的是 VAL 的偏移。内存之间要搬数据,固定走“内存→寄存器→内存”两步。凡是操作数是方括号且没写寄存器的地方,先想清楚长度是字节还是字,该加 BYTE PTR 还是 WORD PTR,别等汇编器报错才回头补。
6. 复习清单:按题号自查的六个动作
复习到后期,最有用的不是再刷一遍题,而是拿一张清单按模块自查。下面这张表把前面几章的重点压成六个动作,每个动作对应一类典型题,做不出来就回到对应章节重看推导过程,而不是重抄答案。
| 自查动作 | 对应考点 | 判断标准 | 错了回看 |
|---|---|---|---|
| 手算 369、4095、32767 三种进制 | 进制转换 | 不查表 3 分钟内全对 | 2.1 降幂法与除法 |
| 默写 -85 的 8 位补码并算六组加减 | 补码与 CF/OF | CF 与 OF 不混 | 2.2 标志判定 |
| 写出 D8H、FFH 的两种解读 | 有无符号双视角 | 两组数都对 | 2.2 两副面孔 |
| 算 3017:000A 和 CS:IP 的物理地址 | 分段与物理地址 | 位数对齐不串位 | 3.2 段左移四位 |
| 推演两次 PUSH 一次 POP 的 SP 与单元内容 | 堆栈 | 高字节在高地址 | 3.4 堆栈规则 |
| 给一条指令判寻址方式并算 PA | 七种寻址与段约定 | BP 那条不按 DS 算 | 4.1、4.2 |
具体怎么用:找一张白纸,合上答案,从上往下逐行做,每行限时三分钟,做完立刻对答案。错的那一行不要只标个记号,要在旁边写清楚错在哪一步——是公式记错,还是寄存器默认段记错,还是进位链断了。写不出原因的就说明这个点没真正过,隔一天再做一次同样的动作。
还有一个更省时间的办法:把题目按“给条件求结果”和“给需求写指令”分成两类。前一类(物理地址、EA、标志位、堆栈变化)全部是套公式,练的是熟练度和细心;后一类(写指令序列、写串操作、写双字运算)练的是把自然语言翻成指令的能力,靠的是模板积累。两类混在一起刷,效率反而低,分开练各打各的靶子更有效。
从那以后我每次复习汇编,都会先拿这张清单走一遍,凡是需要动笔算的地方一律手算,不许心算跳步。吃过一次亏:物理地址那道题心算时少移了一位,整道大题连带后面几问全错,事后复盘发现就是段地址乘 10H 那一步没在纸上写出来。现在不管多简单的地址计算,我都强制自己写出“段×10H+偏移”这一整行,写完再算。希望这份梳理能帮到你,少走一遍我踩过的弯路。
本文还有配套的精品资源,点击获取