【问题标题】:Nasm - weird results when multiplying 2 valuesNasm - 乘以 2 个值时的奇怪结果
【发布时间】:2019-12-26 01:34:19
【问题描述】:

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

在使用mul 指令时,我注意到将两个高数相乘会导致错误的值。例子:

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

【问题讨论】:

    标签: assembly x86 multiplication cpu-registers twos-complement


    【解决方案1】:

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

    原来它来自一个可能使用 Javascript 数字的在线计算器,即带有 53 位尾数的 double-precision 浮点数,它将 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 只是全1,与EAX 的高位相同,因为这就是符号扩展的工作原理。

    【讨论】:

    • 我使用了一个hex calculator,我在互联网上找到它告诉我FFFFFF0*5 = 4FFFFFFB0,这就是为什么我认为edx 应该是4 而不是FFFFFFFF。在这个计算器中FFFFFFFF*FFFFFFFF 的结果也是FFFFFFFE00000000。这是实施错误还是如何解释?
    • @MenNotAtWork: 4FFFFFB00x0FFFFFF0 * 5 的无符号乘法的正确结果,这是您要求在线计算器执行的操作。它不会将输入视为 32 位 2 的补码。 (另外,您刚才在评论中遗漏了一个F)。注意我是如何使用0xfffffff0 - 2^32 来获得0xfffffff0 表示为2 的补码位模式的负数。
    • @MenNotAtWork:FFFFFFFF squared 的在线计算器结果是错误的。也许它使用双精度浮点而不是扩展精度整数?如果它只是用 JavaScript 天真地编写,可能就是这样; Javascript 数字是 IEEE double,因此您可能会遇到舍入错误。如果您包含错误结果的来源,您的问题会更有意义(并且更容易回答)。我真的很想投反对票,因为除了您刚才在评论中提出的内容之外,没有任何理由可以解释为什么您会期望这些错误的结果。
    猜你喜欢
    • 2014-08-17
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多