8086 的 MUL 与 IMUL:无符号/有符号乘法、结果与标志位

维护层,核对日期:2026-09-01。 本文刻意只讨论原始 8086 的单操作数形式。2017 年发布、2023 年最后修改的原文完整保留在文末。其中的 Answers.com 网址仅在存档中作为来源沿革保留;维护版说明以 Intel 文档为依据。

简短结论

在 8086 上,MUL 执行无符号乘法,IMUL 执行有符号二进制补码乘法。两者都只有一个显式的寄存器或内存源操作数,以 ALAX 作为另一个隐式输入,并返回完整的双倍宽度乘积:

  • 字节源操作数:AL × r/m8 → AX
  • 字源操作数:AX × r/m16 → DX:AX

因此,两者的结果布局相同,但数值解释不同。标志位回答的问题也不同:MUL 检查高半部是否为零;IMUL 则检查高半部是否只是低半部的符号扩展。

8086 的准确形式

8086 只有以下四种乘法编码。这里的 r/m 表示显式源操作数可以是寄存器或内存操作数。

源操作数宽度MULIMUL完整结果
8 位F6 /4,无符号 AL × r/m8F6 /5,有符号 AL × r/m8AXAH 为高位,AL 为低位)
16 位F7 /4,无符号 AX × r/m16F7 /5,有符号 AX × r/m16DX:AXDX 为高位,AX 为低位)

在 Intel/NASM 风格语法中,目标寄存器是隐式的:

mul bl          ; unsigned AL × BL -> AX
imul bl         ; signed AL × BL -> AX
mul word [n]    ; unsigned AX × word [n] -> DX:AX
imul word [n]   ; signed AX × word [n] -> DX:AX

单操作数指令不会丢弃高半部。即使 CF 和 OF 表示乘积无法只装入低半部,完整的 16 位或 32 位结果仍保存在文档规定的寄存器或寄存器对中。

相同比特,不同数值

在每条指令执行前,都重新令 AL = 02h,字节源操作数为 FFh。源比特完全相同,但 FFh 作为无符号字节表示 255,作为有符号二进制补码字节则表示 −1。

指令数学运算AX 中的完整结果CF 和 OF
MUL2 × 255 = 51001FEh1,因为 AH = 01h 非零
IMUL2 × (−1) = −2FFFEh0,因为 AH = FFhAL = FEh 的符号扩展

这说明“算法相同”不足以作为编程规则。寄存器布局相似,但有符号解释会同时改变数学乘积和溢出判定。

CF 和 OF 实际表示什么

执行任一种原始 8086 乘法形式后,CF 与 OF 的值相同:

  • 对字节 MUL,仅当 AH = 00h 时两者为 0;对字 MUL,仅当 DX = 0000h 时两者为 0。否则两者都为 1。
  • 对字节 IMUL,仅当 AHAL 的符号扩展时两者为 0;对字 IMUL,仅当 DXAX 的符号扩展时两者为 0。否则两者都为 1。

所以,CF/OF 清零表示:按该指令自身的无符号或有符号解释,乘积能够装入低 8 位或低 16 位。这表示每个有符号乘积的高半部都必须为零。

8086 手册和 Intel 当前参考资料都把这些指令执行后的 SF、ZF、AF、PF 标为未定义。不要用它们给乘积分类;若还需要判断其他条件,应显式测试结果。

可执行的 8 位参考模型

下面这个小型 Python 模型复现了 02h × FFh 的算术过程和文档规定的 CF/OF 规则:

def signed8(value):
    return value - 0x100 if value & 0x80 else value


al, src = 0x02, 0xFF

mul_bits = al * src
mul_cf_of = int((mul_bits >> 8) != 0)

imul_value = signed8(al) * signed8(src)
imul_bits = imul_value & 0xFFFF
imul_low = imul_bits & 0xFF
imul_high = imul_bits >> 8
expected_high = 0xFF if imul_low & 0x80 else 0x00
imul_cf_of = int(imul_high != expected_high)

print(f"MUL  AX={mul_bits:04X}h CF=OF={mul_cf_of}")
print(f"IMUL AX={imul_bits:04X}h CF=OF={imul_cf_of}")

预期输出:

MUL  AX=01FEh CF=OF=1
IMUL AX=FFFEh CF=OF=0

这只是算术参考模型,不是 8086 模拟器;它不模拟指令解码、异常、执行时序或未定义的标志位。

不要把后来的 IMUL 形式误认为 8086 指令

由于 x86 架构在 8086 之后继续发展,Intel 当前参考资料把单操作数、双操作数和三操作数形式写在同一个条目中。1979 年 10 月的 8086 手册,其指令表和解码指南只列出前述基于累加器的单操作数形式。

imul bx          ; original 8086: signed AX × BX -> DX:AX

imul cx, bx      ; later two-operand form: not an original 8086 encoding
imul cx, bx, 10  ; later three-operand form: not an original 8086 encoding

如果没有限制 CPU 目标,现代汇编器可能接受以上三种写法。编写真正的 8086 代码时,应检查所选目标并核对生成的操作码;不能仅因当前手册称某条指令在 legacy mode 下有效,就推断它在历史上的 8086 中已经存在。

实用检查清单

  1. 先确定这些比特表示无符号值(MUL)还是有符号二进制补码值(IMUL)。
  2. 记住隐式输入:字节源操作数使用 AL,字源操作数使用 AX
  3. AXDX:AX 读取完整乘积,不要只看低位寄存器。
  4. 按所选指令的规则使用 CF/OF;把 SF、ZF、AF、PF 视为未定义。
  5. 以 8086 为目标时,只使用单操作数形式并核对生成的编码。

一手资料

---

2017 年原文存档(2023 年最后修改,逐字保留)

下面是 WordPress 导出中的完整可见正文,仅为仓库格式规范化了不可见的行尾空白。外部链接和笼统的 “same algorithm” 表述只作为历史来源沿革保留,并非当前权威依据。


Reference Link:
 http://www.answers.com/Q/What_is_the_basic_difference_between_MUL_and_IMUL_instruction_in_8086_microprocessor

mul is used for unsigned multiplication whereas imul is used for signed multiplication. Algorithm for both are same, which is as follows:
 when operand is a byte:
 AX = AL * operand.
 when operand is a word:
 (DX AX) = AX * operand.

Leave a Reply