理解IMUL指令定义的溢出标志(OF)时出现问题



我对imul在以下指令中设置OF的原因感到困惑

mov  al, 48
mov  bl, 4
imul bl      ; AX = 00C0h, OF = 1

NOT在以下指令中

mov  ax, 48
mov  bx, 4
imul bx      ; DX:AX = 000000C0h, OF = 0

IMUL在结果的下半部分(解释为适当大小的有符号整数(不等于两个输入数字相乘的数学结果时设置溢出标志。

48乘以4的数学结果是192。在imul bl之后留在AL中的值是C0h。作为一个有符号的8位整数,表示数字-64。从数学上讲,192和-64不是同一个数字,所以必须设置溢出。

imul bx之后,AX中剩下的值是00C0h。作为一个有符号的16位整数,表示数字192。因此没有设置溢出标志。

等效地,如果符号扩展到下半部分将产生与完整乘积不同的值,则设置溢出标志。当您将8位值C0h进行符号扩展到16位时,您将得到FFC0h,它不等于00C0h,因此设置了溢出。当您将16位值00C0h进行符号扩展到32位时,您将得到000000C0h,它与实际的32位结果相等,因此不会设置溢出。

等效地,只有当结果的高半部分的每一位都等于低半部分的符号位时,才清除溢出标志。8位值C0h的符号位为1,但高半部分不是FFh,而是00h,因此设置了溢出。16位值00C0h的符号位为0,高半部分为0000h,因此溢出被清除。

OF告诉您是否可以在不更改其值的情况下将双宽度完整结果截断回输入宽度。(当被解释为imul1的2补整数时,mul的无符号二进制整数。(
0xC0是负8位数字的位模式,但0x00C0是正16位数字。

如果您使用imulmul作为其他8位或16位操作(如add(序列的一部分,而没有计划使用结果的高半部分,那么这就是您想要知道的
(或者,如果窄版本足够快,值得进行分支,则可以退回到可以处理更宽尺寸的扩展精度版本。(

如果你已经打算使用输出的全宽,不要检查of/CF;加宽乘法不能在丢失任何输出位的意义上溢出。两个N比特数的乘积总是可以用2N个比特来表示。


脚注1:包括2和3操作数形式,如imul cx, dx, 123,它们不会在任何位置写入高半部分。通常情况下,您会将该形式用于非加宽的有符号或无符号数学,但如果您想检测无符号乘法何时换行,最好只使用mul,即使这会迫使您使用EAX并以EDX:EAX形式输出。参见C和asm-中的imulq和无符号长-长溢出检测

相关内容

最新更新