Nasm - 将 2 个值相乘时出现奇怪的结果

Nasm - weird results when multiplying 2 values

编辑:我正在使用 this 计算器来检查结果,但似乎计算器本身正在计算错误的值,从而导致了这个问题。

在使用 mul 指令时,我注意到将 2 个高数相乘会得到错误的值。示例:

mov eax, 0ffffffffh
mov ebx, 0ffffffffh
mul ebx
; eax:00000001 I expected eax to be 0
; edx:FFFFFFFE

mov eax, 0ffffff00h
mov ebx, 0ffffffffh
mul ebx
; eax:00000100 I expected eax also to be 0
; edx:FFFFFEFF

我知道-1 * -11ffffffffh是负一。但是用无符号乘法将这两个数字相乘不会得到 1,是吗?另一个例子也是如此。

另外,当使用 imul 指令时,我也得到了奇怪的数字,但我认为这是因为有符号的乘法:

mov eax, 0fffffff0h
mov ebx, 5
imul ebx
; eax:FFFFFFB0
; edx:FFFFFFFF ; I expected edx to be 4

你的结果是正常的,你的期望是错误的。 IDK 你错误的期望来自哪里,但是 32 位 mul 的 64 位结果进入 EDX:EAX.

结果是来自一个在线计算器,大概使用了 Javascript 数字,即具有 53 位尾数的 double 精度浮点数,它将 0xfffffffe00000001 舍入到最近的可表示双精度,即 0xfffffffe00000000.

对于带符号的情况,您完全错误地使用了计算器,期望它将您的输入解释为 32 位 2 的补码。


乘法结果的低半部分不取决于您是否将输入解释为带符号的,所以是的,作为快捷方式,我们可以使用 -1 * -1 = 1 在此处获得低半部分。 (这就是为什么英特尔只为 imul 添加有效的非扩展形式,例如 imul eax, edx, -1)。

如果我们简单地在像 calc 这样的扩展精度计算器中尝试一下(在 Ubuntu 中打包为 apcalc,在 Arch 中打包为 calc):

; base2(16)    // ask for hex output as well as decimal

; 0x0ffffffff ^ 2
        18446744065119617025 /* 0xfffffffe00000001 */

; 0x0ffffff00 * 0x0ffffffff
        18446742969902956800 /* 0xfffffeff00000100 */

所以这证实了 CPU 的结果。请记住,奇数乘以奇数是奇数,因此您对 0xffffffff * 0xffffffff 的 EAX=0 猜测也可以这样排除。


对于带符号的,使用任意精度计算器有点棘手:

; (0xfffffff0 - 2^32) * 5
        -80 /* -0x50 */
; . + 2^64                  // get the 64-bit 2's complement bit-pattern for that negative number
        18446744073709551536 /* 0xffffffffffffffb0 */

那个小的无符号数当然分为 0xffffffff0xffffffb0,EDX 只是全一,与 EAX 的高位相同,因为这就是符号扩展的工作原理。