【问题标题】:How to print out output of MUL product?如何打印 MUL 产品的输出?
【发布时间】:2014-01-19 05:39:04
【问题描述】:

我在汇编中使用 MUL (MASM) 将两个整数相乘。

根据 MA​​SM 指令集文档,产品存储在 EDX:EAX 中,即 EDX 和 EAX 寄存器的组合(如果我理解正确的话)。

所以我尝试先打印出 EDX 寄存器的结果,然后再打印 EAX 寄存器以打印出整数。

但是当我得到一个据称超过 32 位(小数点后 10 位)的产品时,我得到了一个奇怪的答案。

例如 100000 * 100000 = 21410065408 ,这是错误的。 但是对于小的乘法,它可以工作。

这是汇编代码:

; MULTIPLY 
    mov eax, var1 ; var1 and var2 from user input
    mul var2 
    mov productResultEDX, edx
    mov productResultEAX, eax


; PRINT RESULT
; mov edx, OFFSET productMsg
    call WriteString
    mov eax, productResultEDX 
    call WriteDec ; prints out EAX register data
    ;mov eax, productResultEAX
    ;call WriteDec

所有变量都声明为 32 位 DWORDS

我是不是搞错了?

【问题讨论】:

  • 请注意,100000 * 100000 的低 32 位是十进制值 141006540​​8。高 32 位是十进制值 2。这解释了你的结果,虽然我不确定你会如何修复您的代码以显示正确的结果。
  • 嗯,解释我的结果是什么意思?
  • 你打印出前 32 位的十进制值,2。然后你打印出低 32 位的十进制值,141006540​​8。将它们粉碎在一起。 2141006540​​8,你的结果。您不能一个接一个地打印它们;你会得到毫无意义的结果。

标签: assembly masm


【解决方案1】:

我相信您正在使用 Irvine 库?那不能打印出 64 位数字,至少我不记得它能够。

所以,除非你想写出自己的 64 位数字打印例程,否则只需使用 c 函数 printf,masm32 将其称为 crt_printf

您可以创建一个 qword 变量来存储 edx:eax,也可以使用结构。

include masm32rt.inc
include msvcrt.inc
includelib msvcrt.lib

BigNum struc
    LoWord  dd  ?
    HiWord  dd  ?
BigNum ends

.data
fmtqw1      db  "100000 * 100000 = %llu",13, 10, 0
fmtqw2      db  "400030 * 500020 = %llu",13, 10, 0

.data?
myqword     dq  ?
BigNumber   BigNum <>

.code
start:

    mov     eax, 100000
    mov     ecx, 100000
    mul     ecx
    mov     dword ptr[myqword], eax
    mov     dword ptr[myqword + 4], edx
    invoke  crt_printf, offset fmtqw1, myqword

    mov     eax, 400030
    mov     ecx, 500020
    mul     ecx    
    mov     BigNumber.LoWord, eax
    mov     BigNumber.HiWord, edx
    invoke  crt_printf, offset fmtqw2, BigNumber

    inkey
    invoke  ExitProcess, 0
end start

【讨论】:

  • 啊,我明白了。是的,我确实在使用 Irvine32 库,我确实忽略了这样一个事实,即我使用的 WriteDec 过程只写出 32 位整数。虽然我原以为两个 32 位整数的乘积会分解为 32 位 EDX reg 和 32 位 EAX 寄存器。很好的收获,谢谢。
【解决方案2】:

你正在做这个算术:100,000 * 100,000。

我们都希望答案是 10,000,000,000(百亿)

现在,恰好有 100 亿,以十六进制表示,

2 540B E400

我的猜测(在这里完全猜测)是您的 WriteStringWriteDec 例程并没有真正意识到您可能有一个很大的(64 位)数字正在尝试打印

这可能有助于澄清一些事情......

百亿是2 540B E400

其中的低 32 位是:540B E400

十进制值是:1,410,065,408

如果您在前面加上数字 2,则该值是您的错误答案,即 21,410,065,408

这是一个建议的测试

使用您现有的代码将这两个数字相乘...

286,331,153 * 15 你应该得到4,294,967,295,它比 4 Gig 小一

现在将第一个数字加 1,然后再做一次乘法;即,

286,331,153 * 15 你应该得到4,294,967,310(即比第一次多了15个)。

如果你的程序显示答案是 115,那么你已经解决了你的错误。

这是发生了什么。

286,331,153 * 15 也是1111,1111h * 0000,000Fh

(逗号是为了清晰起见)

产品是FFFF,FFFFH或刚才提到的四演出(减一)号码

那么,碰巧如果我们将数字加一,就像这样

286,331,154 * 15

我们现在有

1111,1112h * 0000,000Fh

结果为:1 0000 000E

因此,如果您预期的十进制数 4,294,967,310 实际上显示为 115,那么您已经找到了错误。

【讨论】:

    【解决方案3】:

    这是我使用的。这不是最佳的! Nasm 语法,可能需要对 Masm 稍作改动。调整它以满足您的需求。

    ; -------------------------------------- ; u64toda - 在 edx:eax 中转换(64 位)整数 ;到(逗号分隔)十进制表示形式 ; edi 指向的缓冲区中的 ascii 零终止字符串 ;-------------------------------------------- u64toda: 普沙 移动 ebx, edx ;存储高双字 mov esi,0Ah ;准备除以 10 异或 ecx, ecx ;将数字计数归零 jmp highleft ;检查是高字 0 吗? 高词: xchg eax,ebx ;交换高低词 异或 edx,edx ;零 edx 的分歧! div esi ;将高位字除以 10 xchg eax,ebx ;交换他们回来 div esi ;除低字包括余数 推送 edx ;余数是我们的数字 - 保存它 公司 ecx ;数位数 左上角: 或 ebx,ebx jnz高词 左下角: 异或 edx,edx ;零高字 div esi ;将低位字除以 10 推送 edx ;我们的数字 公司 ecx ;数一下 或 eax,eax ; 0了吗? 左下角 cmp ecx,字节 4 ;需要逗号吗? jl write2buf ;不 异或 edx,edx ;除法的零高字 移动 eax,ecx ;位数 mov ebx,3 div ebx 移动 esi,edx ;余数 = 逗号前的数字 测试 edx,edx jnz write2buf ;没有余数? 移动 esi,3 ;那么我们可以写3位数字。 write2buf: 流行音乐;取回数字 - 以正确的顺序 添加 al,30H ;转换为ASCII字符 stosb ;将其写入我们的缓冲区 决定;需要逗号前的数字 jnz 更多数字;还不需要逗号 cmp ecx,2 ;我们到底? jl更多数字;不需要逗号 移动,',';写一个逗号 stosb 移动 esi,03h ;我们很适合另外 3 位数 更多数字: 循环 write2buf ;写更多的数字 - 'em 的 cx 移动,00h ;以零终止缓冲区 stosb 波帕 ret ;-------------------------

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-25
      • 2015-11-04
      • 1970-01-01
      • 1970-01-01
      • 2015-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多