Assembly 我是否应该使用“;mul";或;“伊穆尔”;将有符号数乘以无符号数时?
我发现Assembly 我是否应该使用“;mul";或;“伊穆尔”;将有符号数乘以无符号数时?,assembly,x86,multiplication,unsigned,signed,Assembly,X86,Multiplication,Unsigned,Signed,我发现mul和imul都可以用来将有符号数乘以无符号数 例如: global _start section .data byteVariable DB -5 section .text _start: mov al, 2 imul BYTE [byteVariable] 您可以将imul替换为mul,结果仍然相同(-10) mul和imul在将有符号的数字乘以无符号的数字时是否完全相同,或者它们之间是否存在差异?如注释中所述,上半部分是不同的。如果不关心上半部分,可以在所有形式中
mul
和imul
都可以用来将有符号数乘以无符号数
例如:
global _start
section .data
byteVariable DB -5
section .text
_start:
mov al, 2
imul BYTE [byteVariable]
您可以将imul
替换为mul
,结果仍然相同(-10
)
mul
和imul
在将有符号的数字乘以无符号的数字时是否完全相同,或者它们之间是否存在差异?如注释中所述,上半部分是不同的。如果不关心上半部分,可以在所有形式中使用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
的无符号值表示为有符号格式(我知道这很混乱,但这是我能做的最好的方法),表示为x+256 x_7
(其中x_7
是x
的第7位)。最简单的查看方法可能是拆分它:x+2*128*x7
。这里发生的事情是补偿-128权重,首先通过将位7的值加128次来删除它,然后通过再次执行来一直增加到+128权重,当然这可以在一个步骤中完成
无论如何,将其乘以某个有符号数字y
并计算得出256 x_7 y+xy
,其中xy
是imul
的(双倍宽度)结果,256 x_7 y
意味着“如果x
的符号被设置,则将y
添加到上半部分”,因此可能的实现(未经测试)
当然,您可以对一个操作数进行符号扩展,对另一个操作数进行零扩展,并使用16位乘法(任意,因为上半部分与此无关)。标志的另一种行为。对于MUL:当进位改变上半部分时,OF=CF=1;对于IMUL:OF=CF=1,当进位更改低位的符号位(或仅对2或3个操作数形式的结果中的符号位)时,x86确实有一条将有符号字节乘以无符号字节的指令: 您可以将其视为符号将一个操作数扩展到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也设置了不同的标志:CF=OF=完整结果是否适合下半部分。(即,完整结果是下半部分的零扩展或符号扩展)。对于
imul-reg,r/m
或imul-reg,r/m,imm
,“下半部分”是目的地reg;高半部没有写在任何地方。用不同的值尝试一下,看看你得到了什么。不,结果不一样,可能你只是检查了结果的低半部,结果是一样的。无符号的mul
应该产生502
,结果是ax
@Jester你是对的,ax
在使用mul
时是0x01F6
(502
),在使用imul
时是0xFFF6
(-10
)。始终使用imul reg,r/m32
或imul reg,r/m32,imm
如果您不需要高半部结果;它在现代CPU(1UOP)上更高效,因为它不必在任何地方写入高半音。这不是一个很清楚的描述。英特尔的手册对此做了更好的解释:如果上半部分为非零,则设置CF和OF。如果上半部分不是下半部分的符号扩展,则设置CF和OF。否则他们就被清除了。因此,在这两种情况下,CF=OF=结果是否符合下半部分。(imul的2和3操作数形式仅产生整数乘法的下半部分,但标志设置仍与1操作数形式相同。)
; al has some unsigned value
mov dl, al
sar dl, 7
and dl, [signedByte]
imul BYTE [signedByte]
add ah, dl