News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

DWORD to ASCII

Started by Astro, February 01, 2010, 08:25:10 PM

Previous topic - Next topic

Astro

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.

dedndave

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)

Astro

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.

dedndave

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

Astro

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

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Astro

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.

dedndave

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

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