首页 > 解决方案 > 如何使用乘法的符号扩展?

问题描述

我现在正在学习组装,我完全不知道如何使用符号扩展。我知道,如果您在 AX 中有一个值并且做 MUL 值,它将值乘以 AX,结果在 DX:AX 中,但是我如何访问和使用上部?这对我来说毫无意义。

标签: assemblyx86masmirvine32

解决方案


16 位寄存器保存0000h..FFFFh 范围内的无符号数。此类数的加减结果可能会超出该范围一位,该位由CarryFlag 调节
例如 FFFFh + FFFFh = CF + FFFEh。

乘法的情况有所不同:它可能会溢出 16 位,
例如 FFFFh * FFFFh = FFFE0001h。
这就是为什么使用另一个寄存器(硬连线为 DX)来保存结果的高 16 位的原因。

即使是旧的 16 位处理器 8086 也可以仅使用传统的 16 位寄存器来加|减 32 位数字,但是每个操作需要两条机器指令,并且必须考虑进位标志。32 位数字的下半部分用 计算,ADD|SUB上半部分用计算ADC|SBB

(a*b)+(c*d)例如,让我们计算一下a,b,c,d16 位数字 000Ah、000Bh、000Ch、000Dh 分别在哪里。

MOV AX,000Ah ;
MOV CX,000Bh ; Let CX=000Bh
MUL CX       ; Let DX:AX= a * b = 0000:006Eh
MOV SI,AX  ; Save temporary result DX:AX
MOV DI,DX  ;   into another pair DI:SI.
MOV AX,000Ch
MOV CX,000Dh
MUL CX     ; Let DX:AX = c * d = 0000:009Ch
; Add the temporary result DI:SI to DX:AX.
ADD AX,SI  ; Let AX = 009Ch + 006Eh = 010Ah. CF = 0.
ADC DX,DI  ; Let DX = 0000h + 0000h + CF = 0. CF = 0.

的结果(a*b)+(c*d),即 0000:010Ah,现在位于 DX:AX,CF=0。

我们也可以将 16 位值视为 -32768..+32767 范围内的有符号整数,即 8000h..7FFFh。Intel CPU 8086 不能乘以有符号数,指令IMUL是在 80186 及更高版本中引入的。在没有的情况下,IMUL我们必须将每个数字转换为其绝对值,执行无符号乘法,如果乘数中恰好一个为负,则将无符号乘积转换为其负值。
负值与其绝对(正)值之间的转换由指令NEG提供。要在两个连接的 16 位寄存器中取反 32 位数字,必须再次考虑进位标志:

; Negate DX:AX
NEG DX
NEG AX
SBB DX,0

或者,或者,效率较低

; Negate DX:AX
NOT AX
NOT DX
ADD AX,1
ADC DX,0

但是,正如 Peter Cordes 在评论中所建议的那样,过去 30 年制造的所有 Intel/AMD 处理器都可以直接计算有符号乘法,IMUL因此您最好使用它。


推荐阅读