News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

atou_ex 64bit version

Started by fearless, April 25, 2015, 10:04:50 AM

Previous topic - Next topic

TWell

#30
And using loop ?option epilogue:none
option prologue:none

.code
atou_ex proc

  ; ------------------------------------------------
  ; Convert decimal string into UNSIGNED QWORD value
  ; ------------------------------------------------
  ; argument in RCX

    xor r11, r11
    movzx rax, BYTE PTR [rcx]
    test rax, rax
    jz quit

    xor r10, r10

@@:
    inc r10
    inc rcx
    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx]
    test rax, rax
    jz quit
    cmp r10, 20
    jl @B

    test rax, rax
    jnz out_of_range

  quit:
    lea rax, [r11]      ; return value in RAX
    or rcx, -1          ; non zero in RCX for success
    ret

  out_of_range:
    xor rax, rax        ; zero return value on error
    xor rcx, rcx        ; zero in RCX is out of range error
    ret

atou_ex endp
end
option casemap :none
option epilogue:none
option prologue:none
ifdef __HJWASM__
OPTION STACKBASE:rsp
OPTION WIN64:2
endif
includelib msvcrt64.lib
exit proto :dword
printf proto args:vararg

extern atou_ex :proc

.data
fmt  db "%s %d",13,10,0
qstr db "12345678",0

.code
mainCRTStartup proc
  sub rsp, 30h
  mov rcx, offset qstr
  call atou_ex
  invoke printf,addr fmt, addr qstr, rax
  invoke exit, 0
mainCRTStartup endp

end
EDIT fix as habran suggested

habran

You can use r10 instead of r12 it is a volatile register, r12 is nonvolatile register and should be saved before use.
It is OK in your case, however, if you plan to use this function from other functions you may get in trouble :biggrin:
So, I am not sure were you looking for utoa_ex function or atou_ex function or both :dazzled:
Cod-Father

fearless

I was looking for utoa_ex, i used your version of the atou_ex for atou_ex. Both would be useful for others id imagine.

hutch--

The only version of utoa_ex I have was one of Lingo's from memory and it has magic numbers in it that I don't understand how it works. I will see what I can find.

habran

#34
Here is one that I converted from HJWasm:
It can be used for signed and unsigned qword and can convert to binary, octal, decimal and hex characters
you can call it something like :
mynum = 738h
invoke myqtoa, mynum,ADDR buff, 2, FALSE, FALSE     ;binary
invoke myqtoa, mynum,ADDR buff, 8, FALSE, FALSE     ;octal
invoke myqtoa, mynum,ADDR buff, 10, FALSE, FALSE   ;decimal
invoke myqtoa, mynum,ADDR buff, 16, FALSE, FALSE   ;hexadecimal


.data
  hextbl  db '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'

.code

myqtoa PROC FRAME USES rbx  value:qword, buffer:QWORD,radix:DWORD,sign:DWORD,addzero:DWORD
local tmpbuf[34] :BYTE 
       mov  rbx,rdx      ;buffer
       mov  r10,rdx      ;buffer
       .if (!rcx)
         mov rax,rdx
         mov byte ptr[rax],'0'
         jmp done
       .endif 
       .if (r9b)
         mov  byte ptr [rdx],'-'       
         lea  r10,[rdx+1]       
         neg  rcx
       .endif
      lea  r9,tmpbuf[33]                     
      mov  byte ptr tmpbuf[33],0
      lea  r11,hextbl
      .repeat
        xor   edx,edx                      ;clear rdx               
        mov   rax,rcx                      ;value into rax
        dec   r9                           ;make space for next char
        div   r8                           ;div value with radix (2, 8, 10, 16)
        mov   rcx,rax                      ;mod is in rdx, save result back in rcx
        movzx eax,byte ptr [rdx+r11]       ;put char from hextbl pointed by rdx
        mov   byte ptr [r9],al             ;store char from al to tmpbuf pointed by r9
      .until  (!rcx)                       ;repeat if rcx not clear
      .if (addzero && al > '9')            ;add a leading '0' if first digit is alpha
        mov byte ptr[r10],'0'
        inc r10
      .endif
      lea  r8,tmpbuf[34]                   ;end of the buffer in r8
      sub  r8,r9                           ;that will give a count of chars to be copied
      invoke memcpy,r10,r9,r8              ;call routine to copy
      mov        rax,rbx                   ;return the address of the buffer in rax
done: ret       
myqtoa ENDP
Cod-Father

fearless

Thanks Habran, that works fine. I noticed that the addzero param if set to true displays as the ascii numeric value, and false displays as the hex value which is pretty neat as well. Also, I used RtlMoveMemory in place of the memcpy function, and it works fine with this as well.

habran

No worries fearless :biggrin:
I have modified explanation so that is more clear how it works and how to use it
It was very late last night when I posted it and I've had no time to clarify properly
Cod-Father

habran

#37
Because HJWasm accepts '0x' for hexadecimal numbers it can be written:
      .if (addzero && al > '9')            ;add a leading '0x' if first digit is alpha
         mov word ptr[r10],'x0'
         add r10,2
      .endif

Then you should use : invoke myqtoa, mynum,ADDR buff, 16, FALSE, TRUE   ;hexadecimal

Or if you prefer asm style you can ad this here:
      lea  r9,tmpbuf[33]                     
      mov  byte ptr tmpbuf[33],0
      lea  r11,hextbl
      .f (radix == 16)
         dec r9
         mov byte ptr[r9],'h'
      .endif

      .repeat

If you prefer lower case letters in hexadecimal numbers you can change:
hextbl  db '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
to:
hextbl  db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

Cod-Father

habran

I have optimized myqtoa function so that it doesn't need to call memcpy and it makes it much faster :
Quote
;value is in rcx and contains the number to be printed 
;buffer is in rdx and contains the destiny address where to store the string
;radix is in r8 and it can contain 2 for bin, 8 for octal, 10 for decimal or 16 for hex
;sign is TRUE for negative signed numbers, otherwise FALSE
;set addzero TRUE if you want hex numbers to be used by assembler
myqtoa PROC FRAME USES rbx rdi rsi value:qword, buffer:QWORD,radix:DWORD,sign:DWORD,addzero:DWORD
local tmpbuf[34] :BYTE 
       mov  rbx,rdx                         ;keep the original address of the buffer in rbx
       mov  rdi,rdx                         ;this is working buffer address
       .if (!rcx)                           ;number could be zero
         mov word ptr[rdx],30h              ;print '0',0
         jmp done                           ;the job done
       .endif 
       .if (r9d)                            ;if sign
         mov  byte ptr [rdx],'-'            ;print it out
         lea  rdi,[rdx+1]                   ;increase pointer 
         neg  rcx                           ;make it negative number
       .endif
      lea  rsi,tmpbuf[33]                   ;load last location of tmpbuf                     
      mov  byte ptr tmpbuf[33],0            ;mark the end of string
      lea  r11,hextbl                       ;r11 points to hextable
      ;if you want 'h' at the end, uncomment next 4 lines
      ;.if (radix == 16)                     ;if hex number
      ;  dec rsi                             ;make space for next char
      ;  mov byte ptr[rsi], 'h'              ;end it with 'h'
      ;.endif
      .repeat
        xor   edx,edx                       ;clear rdx               
        mov   rax,rcx                       ;value into rax
        dec   rsi                           ;make space for next char
        div   r8                            ;div value with radix (2, 8, 10, 16)
        mov   rcx,rax                       ;mod is in rdx, save result back in rcx
        movzx eax,byte ptr [rdx+r11]        ;put char from hextbl pointed by rdx
        mov   byte ptr [rsi],al             ;store char from al to tmpbuf pointed by rsi
      .until  (!rcx)                        ;repeat if rcx not clear
      .if (addzero && al > '9')             ;add a leading '0' if first digit is alpha
        mov byte ptr[rdi],'0'
        inc rdi
      .endif
      lea  rcx,tmpbuf[34]                   ;start of the buffer in r8
      sub  rcx,rsi                          ;that will give a count of chars to be copied
      rep movs byte ptr [rdi],byte ptr [rsi];copy bytes to the buffer
      mov        rax,rbx                    ;return the address of the buffer in rax
done: ret       
myqtoa ENDP

Cod-Father

MichaelW

Quote from: rrr314159 on April 27, 2015, 04:26:04 AM
Instead it puts the first 4 args in rcx, rdx, r8, r9...

I don't know what JWASM, or any of the assemblers, actually do, and not to be picking nits, but your description leaves out essential details. For the first four arguments, the integer and FP argument registers are matched by position, RCX:XMM0L, RDX:XMM1L, R8:XMM2L, R9:XMM3L, with the register that does not match the argument type ignored. And IIRC, for unprototyped or vararg functions, the FP values should be duplicated in the matching integer registers.
Well Microsoft, here's another nice mess you've gotten us into.