The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: Astro on February 01, 2010, 08:25:10 PM

Title: DWORD to ASCII
Post by: Astro on February 01, 2010, 08:25:10 PM
Hi,

I know there is a macro that does this already, but here is my take on it. Uses three registers - eax, ecx and edx.

.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\masm32rt.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\masm32rt.lib
includelib \masm32\lib\kernel32.lib

.code

dwrd DWORD 0F2345678h
b BYTE 0,0,0,0,0,0,0,0,0
asciitable BYTE "0123456789ABCDEF"

start:

    sub esp,4
    push esp
    push PAGE_READWRITE
    push 8
    push offset b
    call VirtualProtect
    add esp,4

    mov eax,dwrd

    mov ecx,8
@@:
    mov edx,eax
    and edx,0Fh
    mov edx,[offset asciitable+edx]
    mov byte ptr [offset b+ecx-1],dl
    ror eax,4

    dec ecx
    jnz @B

    print offset b

    xor eax,eax
    ret

end start


Best regards,
Robin.
Title: Re: DWORD to ASCII
Post by: dedndave on February 01, 2010, 08:45:07 PM
no need to place data in the code segent and use VirtualProtect - why not just use the data segment ?
also - no need for a table - Larry had a neat trick on this post...

http://www.masm32.com/board/index.php?topic=12964.0

(although, i wouldn't necessarily use AAM 10h)
Title: Re: DWORD to ASCII
Post by: Astro on February 01, 2010, 08:57:51 PM
Hi,

I put it in the .code segment as it shaved 512 bytes off the final EXE (seemed excessive when all I need is 29 bytes!).

I just did a small mod to eliminate the temporary DWORD for the required pointer destination by VirtualProtect.

I could save another register by unrolling the loop.

Best regards,
Robin.
Title: Re: DWORD to ASCII
Post by: dedndave on February 01, 2010, 09:08:50 PM
you might try using PoLink from Pelle's C compiler package - it will make smaller EXE's
but - nowdays - most drives have cluster sizes of 4 K or larger - 8 K on mine, i think
saving 512 bytes isn't a biggy
the thing is speed - it takes more time to use VirtualProtect if you have a large number of values to convert
with the size of modern drives and memory, speed is better than size
Title: Re: DWORD to ASCII
Post by: Astro on February 01, 2010, 09:31:29 PM
Hmm. polink never creates smaller .EXEs for me. It is still 1536 bytes.

@echo off
echo Building...
ml /c /coff /Cp test.asm
polink /SUBSYSTEM:CONSOLE /LIBPATH:\masm32\lib test.obj
dir test.*
echo Finished!!
pause
Title: Re: DWORD to ASCII
Post by: hutch-- on February 01, 2010, 09:55:54 PM
Robin,

The idea looks OK, I would be inclined to put it inside a procedure without a stack frame and pass to the proc the size data work area you require, otherwise just create a local on the stack with the same capacity. What you have effectively done is merge the code and data sections which saves you the 512 bytes in a small test piece but affords you no size advantage when you have to write this conversion into a working app.
Title: Re: DWORD to ASCII
Post by: Astro on February 02, 2010, 12:00:05 AM
Hi,

Yes - it was just something I was playing with asa a stand-alone piece, but was contemplating making it a proc.

I got it to this:

.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\masm32rt.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

.data
dwrd DWORD 0F2345678h
asciitable BYTE "0123456789ABCDEF"
b BYTE 0,0,0,0,0,0,0,0,0

.code

start:

    align 4
    mov eax,dwrd

    mov ecx,8
@@:
    mov edx,eax
    and edx,0Fh
    mov edx,[offset asciitable+edx]
    mov byte ptr [offset b+ecx-1],dl
    ror eax,4

    dec ecx
    jnz @B

    print offset b

    xor eax,eax
    ret

end start



The following is untested, but I wondered about:

.data
ASCIITable BYTE "0123456789ABCDEF"

.code

dw2ascii proc EndPos:DWORD,StartPos:DWORD,ptrAscBuf:DWORD,ptrDwrdBuf:DWORD

    mov eax,ptrDwrdBuf

    mov ecx,EndPos
    sub ecx,StartPos
@@:
    mov edx,eax
    and edx,0Fh
    mov edx,[offset ASCIITable+edx]
    mov byte ptr [ptrAscBuf+ecx-1],dl
    ror eax,4

    dec ecx
    jnz @B

    ret 16

dw2ascii endp


It needs a bit of work for anything longer than 4 bytes.  :boohoo:  An outer loop in byte steps is probably the solution. Back tomorrow!

Best regards,
Robin.
Title: Re: DWORD to ASCII
Post by: dedndave on February 02, 2010, 01:01:12 AM
i stole Larry Hammick's little snippet to make this proc
it may not even be all that fast - but it is flexible and convenient
in normal use of these kinds of routines, we usually aren't going to convert 10,000 dwords
it follows the conventions of a 32-bit proc, preserving EBX, ESI, EDI, EBP and the DF
the buffer address is returned in EDX for convenience
it is 41 bytes long
if i wanted to speed it up, i would probably align the buffer (as well as the proc)
then, i would write it so it makes 2 dword writes into the buffer instead of 8 bytes - would take a little more code

HxDwd   PROTO   :DWORD,:DWORD

;-----------------------------------------------------------------------------------------

        OPTION  EPILOGUE:NONE
        OPTION  PROLOGUE:NONE

HxDwd   PROC    dwBinVal:DWORD,lpBuffer:DWORD
;
; Convert a binary dword to ASCII hexidemal string
;
; Usage:
;       INVOKE  HxDwd, dwBinVal, lpBuffer
;
;       dwBinVal = binary dword to convert
;       lpBuffer = address of string buffer
;
; Returns:
;       EDX = lpBuffer
;       ECX = 0
;
; EBX, ESI, EDI, EBP, DF preserved

        push    edi
        mov     ecx,8
        mov     edi,[esp+12]
        mov     edx,[esp+8]
        add     edi,ecx

HxDwd0: mov     eax,edx
        and     eax,0Fh
        dec     edi
        cmp     eax,0Ah
        sbb     eax,69h
        das
        shr     edx,4
        mov     [edi],al
        dec     ecx
        jnz     HxDwd0

        mov     edx,edi
        pop     edi
        ret

HxDwd   ENDP

        OPTION  EPILOGUE:EpilogueDef
        OPTION  PROLOGUE:ProEpilogueDef

;-----------------------------------------------------------------------------------------