Question

I'm using MUL in assembly (MASM) to multiply two integers.

According to the MASM Instruction Set docs, the product is stored in EDX:EAX, the combination of the EDX and EAX registers (if I understand correctly).

So I try printing out the result of the EDX register first then the EAX register to print out the whole number.

But when I get a product that supposedly exceeds the 32bits (10 decimal places), I am getting a strange answer.

For example 100000 * 100000 = 21410065408 , which is wrong. But for small multiplications, it works.

Here is the assembly code:

; 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

All variables are declared as 32 bit DWORDS

Am I approaching this wrong?

Était-ce utile?

La solution

I believe you are using the Irvine library? That cannot print out 64bit numbers, at least I don't remember it being able to.

So, unless you want to write out your own 64bit number printing routine, just use the c function printf, masm32 calls it crt_printf.

You can either create a qword variable to store edx:eax, or you can use a structure.

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

64 bit mul results

Autres conseils

You are doing this arithmetic: 100,000 * 100,000.

We all hope the answer is 10,000,000,000 (Ten billion)

Now, it so happens that ten billion, in hex is,

2 540B E400

My guess (totally guessing here) is that your WriteString and WriteDec routines aren't really aware that you may have a large (64 bit) number you are trying to print

This may help clarify a few things...

Ten billions is 2 540B E400

The bottom 32 bits of that are: 540B E400

That value, in decimal, is: 1,410,065,408

That value, if you prepend the digit 2, is your wrong answer, i.e., 21,410,065,408

Here is a suggested test

Use your existing code to multiply these two numbers...

286,331,153 * 15 and you should get 4,294,967,295 which is one less than 4 Gig

Now increase the first number by 1, and do the multiplication again; i.e.,

286,331,153 * 15 and you should get 4,294,967,310 (i.e., 15 more than the first time).

If your program shows that the answer is 115, you have nailed your bug.

Here's what's going on.

286,331,153 * 15 is also 1111,1111h * 0000,000Fh

(the commas are for clarity in reading only)

The product is FFFF,FFFFH or the four gig (minus one) number just mentioned

Now then, it so happens that if we up the number by one, like this

286,331,154 * 15

We now have

1111,1112h * 0000,000Fh

With the result of: 1 0000 000E

So, if your expected decimal number of 4,294,967,310 actually shows up as 115, you have found your bug.

This is what I use. It is NOT optimal! Nasm syntax, may need minor alteration for Masm. Tweak it up to suit your needs.

;    ----------------------------------------
; u64toda - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; ascii zero terminated string in buffer pointed to by edi
;--------------------------------------------
u64toda:
            pusha
            mov ebx, edx     ; stash high dword
            mov esi,0Ah      ; prepare to divide by 10
            xor ecx, ecx     ; zero the digit count
            jmp highleft     ; check is high word 0 ?
highword:
            xchg eax,ebx    ; swap high & low words
            xor edx,edx     ; zero edx for the divide!
            div esi         ; divide high word by 10
            xchg eax,ebx    ; swap 'em back
            div esi         ; divide low word including remainder
            push edx        ; remainder is our digit - save it
            inc ecx         ; count digits
highleft:
            or ebx,ebx
            jnz highword
lowleft:
            xor edx,edx          ; zero high word
            div esi              ; divide low word by 10
            push edx             ; our digit
            inc ecx              ; count it
            or eax,eax           ; 0 yet ?
            jne lowleft
            cmp ecx, byte 4      ; commas needed ?
            jl write2buf         ; nope
            xor edx,edx            ; zero high word for divide
            mov eax,ecx            ; number of digits
            mov ebx,3
            div ebx
            mov esi,edx            ; remainder = number digits before comma
            test edx,edx
            jnz write2buf        ; no remainder?
            mov esi,3             ; we can write 3 digits, then.
write2buf:
            pop eax              ; get digit back - in right order
            add al,30H           ; convert to ascii character
            stosb                ; write it to our buffer
            dec esi               ; digits before comma needed
            jnz moredigits       ; no comma needed yet
            cmp ecx,2             ; we at the end?
            jl moredigits        ; don't need comma
            mov al,','           ; write a comma
            stosb
            mov esi,03h           ; we're good for another 3 digits
moredigits:
            loop write2buf       ; write more digits - cx of 'em
            mov al,00h           ; terminate buffer with zero
            stosb
    popa
            ret
;-------------------------------------
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top