NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: william427 on July 25, 2014, 05:19:48 PM

Title: how to print numbers to 32 bit messagebox
Post by: william427 on July 25, 2014, 05:19:48 PM
to print numbers to a 32 bit messagebox  do you all ways have to convert it ?
thanks
Title: Re: how to print numbers to 32 bit messagebox
Post by: Frank Kotler on July 25, 2014, 06:54:39 PM
Yeah, pretty much. This prints factorials until they overflow (20! ?). It is very old - obsolete "-f obj" format. It might still work... or maybe can be tweaked to work.

Code: [Select]
; assemble: nasm -f obj file.asm
; link: alink -oPE file.obj win32.lib

extern MessageBoxA
extern ExitProcess

segment data use32

    title1: db 'Factorials',0
    title2  db 'Game Over!',0
    overmsg db 'Overflows 64 bits!',0

segment bss use32
    buffer resb 80h

segment code use32

..start

    mov ecx,1          ; start with n=1
nextfact:
                       ; show n
    xor edx,edx        ; clear high dword - we don't want it
    mov eax,ecx        ; edx:eax = n
    mov edi,buffer      ; buffer for "conversion"
    call U64TODA       ; 64 bit number to string at edi
    mov al,'!'
    stosb
    mov al,' '
    stosb
    mov al,'='
    stosb
    mov al,' '
    stosb
   
    mov eax,1          ; set up for mult loop
    push ecx           ; save our old n - loop will decrement ecx
factmult:
    mov ebx,eax        ; save old low dword
    mov eax,edx        ; multiply old high dword
    mul ecx            ; by n, n-1, n-2, etc
    or edx,edx         ; have we got a "too high" dword?
    jnz overflow       ; bail out if we do
    xchg ebx,eax       ; get old low dword back, stash new high dword
    mul ecx            ; multiply the low dword by n, n-1,...
    add edx,ebx        ; add high dword result to high dword from this mult
    jc overflow        ; does that put us over 64 bits?
    loop factmult      ; dec ecx (n) and repeat if not zero

                       ; show n!
    call U64TODA

    push dword 01h ; OK button
    push dword title1
    push dword buffer
    push dword 0
    call MessageBoxA

    cmp eax,1
    jz noexit
    pop ecx
    jmp exit
noexit:

    pop ecx               ; get our last n back
    inc ecx               ; bump it
    jmp nextfact          ; and do the next one

overflow:
    pop ecx            ; we had it saved on stack when we exited loop
    mov esi,overmsg
copy:
    lodsb
    stosb
    or al,al
    jnz copy

    push dword 01h ; OK button
    push dword title2
    push dword buffer
    push dword 0
    call MessageBoxA
exit:
    push dword 0
    call ExitProcess

;--------------------------------------------------------------
; U64TODA - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; zero terminated string in buffer pointed to by edi
; returns with edi pointed to the zero
;-----------------------------------------------------------------
U64TODA :
                push eax
                push ebx
                push ecx
                push edx
                push esi

                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 dword 0 ?
highword:
                xchg eax,ebx    ; swap high & low dwords
                xor edx,edx     ; zero edx for the divide!
                div esi         ; divide high dword by 10
                xchg eax,ebx    ; swap 'em back
                div esi         ; divide low dword 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 dword
                div esi              ; divide low dword by 10
                push edx             ; our digit
                inc ecx              ; count it
                or eax,eax           ; 0 yet ?
                jne lowleft
                cmp ecx,04h          ; commas needed ?
                jl write2buf         ; nope
                xor edx,edx          ; zero high dword for divide
                mov eax,ecx          ; number of digits
                mov ebx,3
                div ebx
                mov esi,edx          ; remainder = number digits before comma
                or 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
                dec edi

                pop esi
                pop edx
                pop ecx
                pop ebx
                pop eax
                ret
;-------------------------------------------------------------

This is far from optimized. Used to work, as I recall. Might, still. Good luck!

Best,
Frank

Title: Re: how to print numbers to 32 bit messagebox
Post by: nullptr on July 26, 2014, 05:59:26 AM
You can use wsprintf to convert binary digit and paste it into string:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms647550%28v=vs.85%29.aspx
Code: [Select]
;assemble:
;nasm.exe -f win32 wsprintf.asm -o wsprintf.obj
;link:
;golink /entry main wsprintf.obj user32.dll

bits 32

extern MessageBoxA
extern wsprintfA

MB_OK EQU 0

section .data

Caption DB "wsprintf test",0
Fmt DB "ASCII number: %u",0

section .bss
MsgOut resb 32


section .text

main:
mov eax, 123456789

push eax
push Fmt
push MsgOut
call wsprintfA

push MB_OK
push Caption
push MsgOut
push 0
call MessageBoxA

ret
Title: Re: how to print numbers to 32 bit messagebox
Post by: gammac on July 26, 2014, 11:25:12 AM
wsprintf is __cdecl, the caller have to clean the stack.
Title: Re: how to print numbers to 32 bit messagebox
Post by: nullptr on July 26, 2014, 12:37:31 PM
Quote
wsprintf is __cdecl, the caller have to clean the stack.
Yes, sorry i forgot to restore esp. After call wsprintfA should be:

Code: [Select]
add esp, 4*3

thanks gammac.
Title: Re: how to print numbers to 32 bit messagebox
Post by: Frank Kotler on July 26, 2014, 12:50:15 PM
... and besides, it doesn't put commas in. :)

Seriously, thanks for the example and the correction. I would have expected that with the stack altered, ending with "ret" would have crashed hard. Didn't it? I was under the impression that "ExitProcess" was the prefered way to exit.

Still, one way or another, yeah you have to convert the numbers.

Best,
Frank

Title: Re: how to print numbers to 32 bit messagebox
Post by: nullptr on July 26, 2014, 01:58:22 PM
Quote
Seriously, thanks for the example and the correction. I would have expected that with the stack altered, ending with "ret" would have crashed hard. Didn't it? I was under the impression that "ExitProcess" was the prefered way to exit.
It runs like lightning - lol. No crash at all. But that's true it should crash without ExitProcess.

 I'm rather user of other assemblers than NASM so sometimes confused about it. I took idea of "ret" at the end becuase I saw some GCC linked examples that are exiting in this way(doesn't remeber them well so maybe those are my delusions :) ).

Sorry for my mess. Maybe i'll became programmer in next life. Anyway thanks for corrections.
Title: Re: how to print numbers to 32 bit messagebox
Post by: gammac on July 26, 2014, 03:05:58 PM
I would have expected that with the stack altered, ending with "ret" would have crashed hard. Didn't it? I was under the impression that "ExitProcess" was the prefered way to exit.

Yes, it'll crashes and yes, ExitProcess is the prefered way to exit.