我发现mul
和imul
都可以用来将有符号数乘以无符号数。
例如:
global _start
section .data
byteVariable DB -5
section .text
_start:
mov al, 2
imul BYTE [byteVariable]
您可以将imul
替换为mul
,结果仍然相同(-10
)。
将签名的号码与无符号号码相乘时,mul
和imul
是否完全相同,或者它们之间是否存在差异?
答案 0 :(得分:3)
正如评论中所提到的,上半部分是不同的。如果你不关心上半部分,你可以使用mul
或imul
的所有形式(单操作数形式产生上半部分,但在这种情况下你会忽略它。)
如果你关心上半部分,那么mul
和imul
都不能正常工作,因为它们只是将unsigned * unsigned和signed * signed相乘,但你可以很容易地修复它。
考虑有符号字节的位权重为-128,64,32,16,8,4,2,1,而无符号字节的位权重 + 128,64 ,32,16,8,4,2,1。所以你可以用签名格式表示x
的无符号值(我知道这很令人困惑,但它是我能做的最好的){{{ 1}}(其中x + 256 x_7
是x_7
的第7位)。最简单的方法是分割它:x
。这里发生的是补偿-128的重量,首先通过将第7位的值加128次然后再一次将其移至+128重量来移除它,当然这可以做到一步到位。
无论如何,将其与某个已签名的数字x + 2 * 128 * x_7
相乘并进行处理会得到y
,其中256 x_7 y + xy
是xy
和{{的{双倍宽度]结果如果imul
的符号设置为"则表示"将256 x_7 y
添加到上半部分,因此可能的实现是(未测试)
y
当然,您可以对一个操作数进行符号扩展,对另一个操作数进行零扩展,并使用16位乘法(任何,因为上半部分与此无关)。
答案 1 :(得分:0)
标志的另一行为。对于MUL:当进位改变上半部分时,OF = CF = 1;对于IMUL:OF = CF = 1,当进位更改低位的符号位(或只是2或3个操作数形式的结果的符号位)
答案 2 :(得分:0)
x86 确实有一条指令,将有符号字节乘以无符号字节:SSSE3 pmaddubsw
。
您可以将其视为将一个操作数符号扩展为16位,将另一个操作数零扩展为16位,然后执行NxN-> N位乘法。 (对于每个SIMD元素)。
它还会从相邻字节中水平添加单词乘积对,但是如果用零(punpcklbw
或pmovzxbw
)解包输入,则可以分别获得每个乘积。
当然,如果您有SSE4.1,那么如果您不愿意,可以pmovsxbw
一个输入,pmovzxbw
另一个输入来填充常规的16位pmullw
配对。
但是,如果您只想获得一个标量结果,则最好的选择是movsx
/ movzx
,以提供定期的非扩展imul reg, reg
。
正如Harold指出的那样,mul r/m
和imul r/m
的加倍乘法以相同的方式对待它们的两个输入,因此它们都不起作用(除非已知有符号输入为非负,或者无符号输入为已知没有设置高位,因此您可以对它们进行相同的对待。)
mul和imul对FLAGS的设置也不同:CF = OF =整个结果是否适合下半部分。 (即完整的结果是下半部分的零扩展或符号扩展)。对于imul reg,r/m
或imul reg, r/m, imm
,“下半部分”是目标寄存器;高半部分没有写在任何地方。