维护层,核对日期:2026-09-01。 本文刻意只讨论原始 8086 的单操作数形式。2017 年发布、2023 年最后修改的原文完整保留在文末。其中的 Answers.com 网址仅在存档中作为来源沿革保留;维护版说明以 Intel 文档为依据。
Table of Contents
简短结论
在 8086 上,MUL 执行无符号乘法,IMUL 执行有符号二进制补码乘法。两者都只有一个显式的寄存器或内存源操作数,以 AL 或 AX 作为另一个隐式输入,并返回完整的双倍宽度乘积:
- 字节源操作数:
AL × r/m8 → AX; - 字源操作数:
AX × r/m16 → DX:AX。
因此,两者的结果布局相同,但数值解释不同。标志位回答的问题也不同:MUL 检查高半部是否为零;IMUL 则检查高半部是否只是低半部的符号扩展。
8086 的准确形式
8086 只有以下四种乘法编码。这里的 r/m 表示显式源操作数可以是寄存器或内存操作数。
| 源操作数宽度 | MUL | IMUL | 完整结果 |
|---|---|---|---|
| 8 位 | F6 /4,无符号 AL × r/m8 | F6 /5,有符号 AL × r/m8 | AX(AH 为高位,AL 为低位) |
| 16 位 | F7 /4,无符号 AX × r/m16 | F7 /5,有符号 AX × r/m16 | DX:AX(DX 为高位,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 |
|---|---|---|---|
MUL | 2 × 255 = 510 | 01FEh | 1,因为 AH = 01h 非零 |
IMUL | 2 × (−1) = −2 | FFFEh | 0,因为 AH = FFh 是 AL = FEh 的符号扩展 |
这说明“算法相同”不足以作为编程规则。寄存器布局相似,但有符号解释会同时改变数学乘积和溢出判定。
CF 和 OF 实际表示什么
执行任一种原始 8086 乘法形式后,CF 与 OF 的值相同:
- 对字节
MUL,仅当AH = 00h时两者为 0;对字MUL,仅当DX = 0000h时两者为 0。否则两者都为 1。 - 对字节
IMUL,仅当AH是AL的符号扩展时两者为 0;对字IMUL,仅当DX是AX的符号扩展时两者为 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 中已经存在。
实用检查清单
- 先确定这些比特表示无符号值(
MUL)还是有符号二进制补码值(IMUL)。 - 记住隐式输入:字节源操作数使用
AL,字源操作数使用AX。 - 从
AX或DX:AX读取完整乘积,不要只看低位寄存器。 - 按所选指令的规则使用 CF/OF;把 SF、ZF、AF、PF 视为未定义。
- 以 8086 为目标时,只使用单操作数形式并核对生成的编码。
一手资料
- Intel® 64 and IA-32 Architectures Software Developer's Manual,Volume 2A:`IMUL—Signed Multiply`——Intel 当前指令条目给出了单操作数结果和符号扩展测试,并另行说明后来的形式。
- Intel® 64 and IA-32 Architectures Software Developer's Manual,Volume 2B:`MUL—Unsigned Multiply`——Intel 当前指令条目给出了隐式操作数、双倍宽度目标和高半部标志规则。
- _The 8086 Family User's Manual_,1979 年 10 月——Bitsavers 保存的 Intel 出版物 9800722-03 的存档扫描件;乘法说明见纸本页码 2-36 至 2-37,原始操作码/解码表见第 4 章。
---
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.
