ICS 与 8086 复习 07:算术逻辑指令与标志位
同样的八位加法,既可能表示 127+1,也可能表示 255+1。CPU 按位完成运算,再用标志位记录结果特征;程序选择有符号还是无符号解释,决定了应该检查哪个标志。
复习这一章,最有效的方法是把指令功能与标志位放在一起分析。每次先固定运算宽度,写出截断后的结果,再判断 CF、OF、SF、ZF。本文所有指令都限定在 8086,采用 Intel/MASM 语法。
CF 与 OF 分别回答什么
对 n 位结果,无符号范围为 0 至 2^n−1,补码有符号范围为 −2^(n−1) 至 2^(n−1)−1。
CF 反映无符号加法的进位、减法的借位;OF 反映有符号结果能否用当前位数表示。SF 是结果最高位,ZF 表示结果是否为零。SF 为 1 只能说明结果位串最高位为 1,不能单独证明数学上的有符号结果为负,因为有符号运算可能已经溢出。
以八位加法为例:
| 运算 | 截断结果 | CF | OF | 解释 |
|---|---|---|---|---|
7FH+01H |
80H |
0 | 1 | 127 加 1 超出有符号上界 |
FFH+01H |
00H |
1 | 0 | 无符号 256 装不下;有符号 −1 加 1 正常 |
80H+80H |
00H |
1 | 1 | 两种解释都超出对应范围 |
加法的 OF 可用“同号相加得到异号”判断。减法则看“两个操作数异号,结果符号与被减数不同”。例如八位 80H−01H=7FH,无符号 128 减 1 不需要借位,所以 CF=0;有符号 −128 减 1 无法表示,所以 OF=1。
PF 检查结果低八位中 1 的个数是否为偶数,AF 记录低半字节间的进借位。它们主要用于指定标志分析或十进制调整题,不能把 PF 当作整个 16 位结果的奇偶性。
多字运算靠进位链衔接
ADD 执行加法,ADC 额外加上当前 CF;SUB 执行减法,SBB 额外减去当前 CF。处理多字整数时,先算低字,再把低字的进位或借位带到高字。
设一个 32 位数在 DX:AX 中,另一个在 BX:CX 中:
DX:AX = 0002:F365H
BX:CX = 0005:8100H
执行:
add ax, cx
adc dx, bx
第一步,F365H+8100H=17465H,AX 保留低 16 位 7465H,CF=1。第二步,0002H+0005H+1=0008H,所以最终结果是 0008:7465H。
不能把第二条改成 ADD,否则低字产生的进位会丢失。两条之间也不能随意插入会修改 CF 的指令。
还要注意,多字运算最后一条 ADC 的 ZF 只反映高字结果是否为零,不能直接据此断言整个 32 位结果为零。要判断整个数,需要结合高低字。
INC、DEC 会更新部分条件标志,却保留 CF。CMP 按减法设置标志而不保存差值。NEG 计算 0−操作数:输入为零时 CF=0,否则 CF=1;八位 80H 或十六位 8000H 取负时 OF=1,因为最小负数的正数形式装不下。
乘除法先写出隐含寄存器
8086 的 MUL、IMUL 使用一个显式操作数,不能直接套用后代处理器的多操作数 IMUL。
| 显式操作数宽度 | 乘法 | 除法 |
|---|---|---|
| 字节 | AL×SRC → AX |
AX÷SRC → AL商,AH余数 |
| 字 | AX×SRC → DX:AX |
DX:AX÷SRC → AX商,DX余数 |
MUL、DIV 按无符号解释;IMUL、IDIV 按有符号解释。MUL 的高半部分非零时 CF=OF=1;IMUL 的高半部分不能由低半部分符号扩展得到时 CF=OF=1。其他条件标志不能用来判断乘法结果。
做除法之前,先确认被除数宽度。一个 16 位无符号数要除以一个字,常用 xor dx,dx 把被除数扩展到 DX:AX;16 位有符号数则用 CWD 做符号扩展。不能把清 DX 当作所有除法的固定步骤,因为一个本来就有意义的 32 位被除数,其高字不能丢弃。
例如计算有符号 −9÷4:
mov ax, -9
cwd
mov bx, 4
idiv bx
CWD 后 DX:AX 为 FFFF:FFF7H,表示 32 位的 −9。IDIV 后商 AX=FFFEH,即 −2;余数 DX=FFFFH,即 −1,满足 −9=(−2)×4+(−1)。
除数为零或商超出目标寄存器可表示范围,都会触发除法错误。DIV、IDIV 的条件标志无定义,不能通过检查 OF 来确认除法是否成功。
CBW 是 AL 到 AX 的符号扩展,CWD 是 AX 到 DX:AX 的符号扩展。例如从 AX=BA45H 出发,单独执行 CBW 得到 0045H;单独执行 CWD 得到 FFFF:BA45H。如果先 CBW 再 CWD,后者看到的已经是 0045H,因此结果为 0000:0045H。
位操作和移位的判分细节
AND 用于清位,OR 用于置位,XOR 用于翻转位,TEST 执行按位与但不回写,NOT 按位取反且不改标志。例如:
and al, 0fch ; 清除第0、1位
or al, 20h ; 置第5位
xor al, 03h ; 翻转第0、1位
test al, 01h ; 检查最低位,AL不变
AND、OR、XOR、TEST 都把 CF、OF 清零,并据结果设置 SF、ZF、PF。xor ax,ax 可以清零,但它会改标志;需要保留标志时,不能无条件替代 mov ax,0。
SHL 与 SAL 是同一操作,左侧移出、右侧补零;SHR 右移补零;SAR 右移补原符号位。非零移位时,CF 接收最后移出的位。一次移位时 OF 有定义,多次移位时不应臆测 OF;移位次数为零时标志不变。Intel 指令手册 SAL/SAR/SHL/SHR
8086 的计数操作数只能直接写 1,或放入 CL:
mov cl, 4
shl ax, cl
限定 8086 时不能直接写 shl ax,4。ROL、ROR 把移出位绕回另一端,RCL、RCR 则把 CF 一起纳入循环;它们与普通移位的补入规则不同。
SAR 对负数相当于向负无穷取整。例如 −9 算术右移两位得到 −3,而 IDIV 除以 4 得到 −2,二者不能对负数直接互换。多字逻辑左移一位则可用 shl ax,1、rcl dx,1,把低字移出的位送入高字最低位。
十进制调整题先确认编码
压缩 BCD 每四位表示一个十进制数字,34H 表示十进制 34,而不是十六进制数的普通整数解释。非压缩 BCD 每字节放一位十进制数;ASCII 数字字符还带有 30H 的编码偏置,不能直接当作数值 0—9。
两个合法压缩 BCD 数在 AL 中做 ADD 后,可以紧接 DAA 调整。例如 34H+59H 先得到 8DH,DAA 再得到 93H,表示十进制 93。DAS 对应减法;AAA、AAS、AAM、AAD 对应课件中的非压缩 BCD 调整。不要把 DAA 当成任意二进制数到十进制文本的通用转换器。
常见误区
最常见的失分是用 CF 判断有符号溢出,或把 OF 当作最高位进位。乘除题则容易漏掉 AH、DX 中原有内容,导致实际被除数与题目设想不同。
另外,“执行后不改标志”和“标志无定义”有本质区别:前者允许继续使用原标志,后者不允许推断其值。程序分析时应逐条记录最后一次有效设置相关标志的指令。
自测与答案
- 八位
AL=7FH,执行add al,1后,AL、CF、OF、SF、ZF 各是多少? - 初始 CF=1,执行
mov ax,0、inc ax后,AX 和 CF 是多少?若把 INC 改为add ax,1呢? - 有符号 −9 用 SAR 右移两位,与用 IDIV 除以 4,各得到什么商?
答案:1. AL=80H,CF=0、OF=1、SF=1、ZF=0。2. 原序列 AX=1、CF=1;改用 ADD 后 AX=1、CF=0。3. SAR 得到 −3,IDIV 的商为 −2,余数为 −1。
对应课件
《汇编语言 第3章.pptx》:第 70 页符号扩展,第 71—84 页算术与乘除,第 85—90 页 BCD,第 91—100 页逻辑、移位与循环移位。页码按文件中的幻灯片顺序计。
讨论这篇文章
关于《ICS 与 8086 复习 07:算术逻辑指令与标志位》的补充、不同意见或延伸话题,都可以留在这里。
滚动到这里时自动载入留言。