The MASM Forum

64 bit assembler => 64 bit assembler. Conceptual Issues => Topic started by: fearless on April 25, 2015, 10:04:50 AM

Title: atou_ex 64bit version
Post by: fearless on April 25, 2015, 10:04:50 AM
Ive modified Paul Dixon's orignal atou_ex function for use with 64bit JWasm64. Return value in rax. Done some basic tests and it seemed to work - so fingers crossed that it continues to. If anything looks out of place let me know.

.686
.MMX
.XMM
.x64

option casemap : none
option win64 : 11
option frame : auto
option stackbase : rsp

atou_ex  PROTO :QWORD

.code

;--------------------------------------------------------------------------------------------------------------------
; Convert ascii string pointed to by String param to unsigned qword value. Returns qword value in rax.
; Original code for atou_ex by Paul Dixon. Converted to 64bit support by fearless 2015
;--------------------------------------------------------------------------------------------------------------------

atou_ex PROC FRAME USES RCX RDX String:QWORD

  ; ------------------------------------------------
  ; Convert decimal string into UNSIGNED QWORD value
  ; ------------------------------------------------

    mov rdx, String

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

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+1]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+2]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+3]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+4]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+5]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+6]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+7]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+8]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+9]
    test rax, rax
    jz quit

    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+10]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+11]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+12]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+13]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+14]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+15]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+16]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+17]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+18]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+19]
    test rax, rax
    jz quit
   
    lea rcx, [rcx+rcx*4]
    lea rcx, [rax+rcx*2-48]
    movzx rax, BYTE PTR [rdx+20] ; if > 20 ascii chars in length will fall out.
    test rax, rax
    jnz out_of_range

  quit:
    lea rax, [rcx]      ; 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
Title: Re: atou_ex 64bit version
Post by: Gunther on April 26, 2015, 03:55:41 AM
Hi fearless,

why do you use a stack frame? Is it necessary?

Gunther
Title: Re: atou_ex 64bit version
Post by: fearless on April 26, 2015, 07:19:59 AM
Hi Gunther,

Not sure if it is necessary, tbh i just added it in to most of the functions i created and seemed to compile ok, i just kept my fingers crossed. Maybe others will know if its needed or if there is other optional (maybe more optimal?) ways of calling/defining functions to use. Im still new to the 64bit stuff, so my fingers have been crossed a lot lately ;-)
Title: Re: atou_ex 64bit version
Post by: Gunther on April 26, 2015, 08:47:41 PM
Hi  fearless,

Quote from: fearless on April 26, 2015, 07:19:59 AM
Not sure if it is necessary, tbh i just added it in to most of the functions i created and seemed to compile ok, i just kept my fingers crossed. Maybe others will know if its needed or if there is other optional (maybe more optimal?) ways of calling/defining functions to use. Im still new to the 64bit stuff, so my fingers have been crossed a lot lately ;-)

I think that by following the calling conventions, a stack frame isn't necessary. The details can be found here (http://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention). Please notice the differences between MS calling convention and the System V AMD64 ABI. Also new is the  MS __vectorcall (http://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_vectorcall). It supports homogeneous vector aggregate (HVA) values. I haven't used that call until now, because it wasn't necessary. But in some situations it could be quite well.

Gunther
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 26, 2015, 11:24:25 PM
Since fearless has no local variables, no stack frame will be generated anyway. Habran can correct me if wrong; certainly, it shouldn't be generated. So you can leave that option on always, will only have effect when it's needed. It's also involved with SEH, but I don't think that's relevant here.

In general stack frame is not necessary for fastcall convention. Arguments are (well, can be) pushed on stack, like 32-bit; main difference is first four are also in registers RCX etc. Stack frame, as I say, is for local variables and isn't directly concerned with calling conventions.

MS "vectorcall" - in assembler of course we can use SIMD's to pass args without Bill's gracious permission; I've been doing it as a matter of course.

U know, fearless, u don't have to "uses" RCX and RDX since they're volatile. In fact since rcx is used for (the first) argument, I don't think "uses" is of any use. And, since rcx already contains "String" it would make more sense to switch the roles of rcx and rdx in your code.

BTW fearless, (answering the other thread) no I don't have vKim 64-bit macros handy! Someday when I have spare time it would be an interesting project
Title: Re: atou_ex 64bit version
Post by: dedndave on April 27, 2015, 01:19:05 AM
local variables OR passed arguments will cause generation of a prologue/epilogue
Title: Re: atou_ex 64bit version
Post by: nidud on April 27, 2015, 01:28:00 AM
deleted
Title: Re: atou_ex 64bit version
Post by: fearless on April 27, 2015, 03:54:48 AM
I think i was mainly using the FRAME as a just in case measure, not really understanding its inner working, but hoping that including it would be ok. I used it primarily when doing stuff for the x64dbg plugins, the callback functions crashed without the FRAME, so when i put it back in, i also ended up putting it everywhere else in other functions as well. Probably a habit of declaring USES X Y Z now as well, just in case  - even tho as you say the rcx rdx r8 and r9 are volitile and are used anyhow

When i was converting the orignal code for atou_ex, it used the edx and ecx registers, and so i didnt want to modify too heavily or change the flow of the code use of registers that much, i was hoping to just expand the registers to their full 64bit width, and adjust the start of the code that had the push ebp stuff (commented them out) to use the params directly. Seemed to work so just left it as listed above.

Ive had a look at the utoa_ex function as well, but so far its proved a little more troublesome - i can get it to work sort of, but only for the dword equivalent length of a number is changed to its ascii representation so far.
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 27, 2015, 04:26:04 AM
It's a little confusing ...

To me the word "stack frame" means using rbp (or, ebp) to reserve space below the entry point on the stack for local variables. (Or other purposes, see SEH). However I found an MSN reference (https://msdn.microsoft.com/en-us/library/ms235286.aspx) which uses the word "frame" in the context of merely putting arguments on the stack - like dedndave (who's implying that just having a prologue/eliplogue constitutes a "frame"). So, let's ignore the language.

What JWASM does when option frame : auto is used - OR, not used - is this. If there are no local variables (or, other complications like RtlAddFunctionTable() - not applicable here; or non-leaf, see below) then it doesn't use rbp to create what I've traditionally called a frame. Instead it puts the first 4 args in rcx, rdx, r8, r9, reserve 20h byte on stack for them, any other args on stack above (ignoring other complications which aren't applicable here). When you do have locals JWasm creates an "rbp frame" whether the option is on or not. In other words, the option is ignored.

But when the function is not a leaf function, the option causes an "rbp frame", due to Habran's latest work. Again - NAH (not applicable here). I believe that's the only difference with the "auto" option. See Habran's posts in the JWasm development forum for examples.

Habran of course knows exactly so if I'm wrong pls correct me. We mortals can simply check the code generated and see what I mean. AFAIK fearless's code will compile the same with or without that option; and so will the invoke used to call it. I should check it myself but I'll take a chance on being wrong, I'm used to it.

nidud, not just C-proc, an assembler proc also needs to use the stack for arguments if you're using JWasm invoke, and following new ABI.

p.s. just checked JWasm, seems it also puts first args on stack, which is not required by ABI but makes sense.
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 27, 2015, 04:34:20 AM
@fearless, I posted the above b4 seeing your post - sure your code will work as it is. Just makes more sense to use rcx for String since it's there already.

p.s. the frame has something to do with SEH (not sure what exactly) so makes sense that when working with a debugger it's necessary.
Title: Re: atou_ex 64bit version
Post by: nidud on April 27, 2015, 05:12:37 AM
deleted
Title: Re: atou_ex 64bit version
Post by: habran on April 27, 2015, 05:54:10 AM
Listen to rrr314159, he is a teacher ;)
Title: Re: atou_ex 64bit version
Post by: Gunther on April 27, 2015, 06:09:16 AM
Hi nidud,

Quote from: nidud on April 27, 2015, 05:12:37 AM
Is this correct ?

it's all described here (http://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention) and in post #3 above.

Gunther
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 27, 2015, 07:53:37 AM
Listen to Habran, he is a doer, much better than a teacher

@nidud, no that's not quite it.

mov rcx,1 ; load regs with 4 args
mov rdx,2
mov r8,3
mov r9,4
sub rsp,8*8 ; reserve shadow space for first four, plus "real" space for last 4
mov [rsp+24],5 ; load stack with 4 args, 5 thru 8
mov [rsp+16],6
mov [rsp+8],7
mov [rsp+0],8
call proc8 ; make the call
add rsp,8*8 ; release stack

It could be done like this, modifying your example minimally. Although JWasm doesn't do it exactly that way, the effect is the same. Of course this assumes "5", "6" etc are registers else the mov's won't work ...

And the called proc doesn't allocate stack, that's already been done. But it may spill rcx, rdx, r8 r9 to their (already allocated) space on the stack - that's what it's there for. That's as you show, except you have them in upside-down order. And in this case we wouldn't call them "locals" they're saved ("spilled") args.

JWasm doesn't put rcx etc on the stack when calling. But when they're used in the proc, it spills them first. Me, I write my own invoke, and always put them on the stack when calling, except when speed is really critical.

Anyway this means that even if fearless xor's rcx before putting String in rdx, it will work OK, because rcx gets saved before xor'ing. Seems strange but if JWasm does it that way it must be good!

If there were locals - which you don't show - then space would be used on the stack, but it goes below the entry point, not above (as for args), and uses rbp to reference them.

There are more details, some args are pointed to not passed, stack alignment is critical (above discussion assumes it's already aligned) and then there's SEH which I haven't really gotten to yet

BTW Gunther's reference (Wikipedia) is incomplete and has the standard mistake re. floating point (which I've mentioned often) - seems to be required for any write-up on the net. Use MSDN for info, the only place I've seen that gets this one right
Title: Re: atou_ex 64bit version
Post by: habran on April 27, 2015, 10:21:30 AM
Here is one way to do that:

  atou_ex PROC FRAME String:QWORD   
    xor eax, eax
  .repeat
    movzx rdx, BYTE PTR [rcx]
    test rdx, rdx
    .break .if (ZERO?)
    lea rax, [rax+rax*4]
    lea rax, [rdx+rax*2-48]
    inc rcx
  .until FALSE
    mov rcx, -1          ; non zero in RCX for success
    ret                  ; rax contains the number
atou_ex endp

atou_ex:
0000000001041147 33 C0                xor         eax,eax 
0000000001041149 48 0F B6 11          movzx       rdx,byte ptr [rcx] 
000000000104114D 48 85 D2             test        rdx,rdx 
0000000001041150 74 0E                je          atou_ex+19h (01041160h) 
0000000001041152 48 8D 04 80          lea         rax,[rax+rax*4] 
0000000001041156 48 8D 44 42 D0       lea         rax,[rdx+rax*2-30h] 
000000000104115B 48 FF C1             inc         rcx 
000000000104115E EB E9                jmp         atou_ex+2h (01041149h) 
0000000001041160 48 C7 C1 FF FF FF FF mov         rcx,0FFFFFFFFFFFFFFFFh 
0000000001041167 C3                   ret

You can try to add a counter :biggrin:
Title: Re: atou_ex 64bit version
Post by: habran on April 27, 2015, 02:01:10 PM
Here is one with the counter:

  atou_ex PROC FRAME String:QWORD   
    xor eax,eax
    xor edx,edx
  .repeat
    movzx r8, BYTE PTR [rcx+rdx]
    .if (!r8)
      mov rcx, -1          ; non zero in RCX for success
      jmp done
    .endif
    lea rax, [rax+rax*4]
    lea rax, [r8+rax*2-48]
    inc edx
  .until (edx==20)
  xor ecx,ecx              ;zero means out of range error
done:     
    ret                    ; rax contains the number
atou_ex endp

atou_ex:
0000000000981147 33 C0                xor         eax,eax 
0000000000981149 33 D2                xor         edx,edx 
000000000098114B 4C 0F B6 04 0A       movzx       r8,byte ptr [rdx+rcx] 
0000000000981150 4D 85 C0             test        r8,r8 
0000000000981153 75 09                jne         atou_ex+17h (098115Eh) 
0000000000981155 48 C7 C1 FF FF FF FF mov         rcx,0FFFFFFFFFFFFFFFFh 
000000000098115C EB 12                jmp         atou_ex+29h (0981170h) 
000000000098115E 48 8D 04 80          lea         rax,[rax+rax*4] 
0000000000981162 49 8D 44 40 D0       lea         rax,[r8+rax*2-30h] 
0000000000981167 FF C2                inc         edx 
0000000000981169 83 FA 14             cmp         edx,14h 
000000000098116C 75 DD                jne         atou_ex+4h (098114Bh) 
000000000098116E 33 C9                xor         ecx,ecx 
0000000000981170 C3                   ret
Title: Re: atou_ex 64bit version
Post by: habran on April 27, 2015, 06:50:59 PM
Here is one more complex:

;this function can convert up to 128 bit:
;binary:  b or y  base = 2
;octal:   o or q  base = 8
;decimal: d or t  base = 10
;hexadecimal:  h  base = 16
;hsize contains number of chars
;dst contains converted number in little endian
;that means you can load register directly from memory
;like mov rax,dst
hatoi128 PROC FRAME USES rbx src:QWORD,dst:QWORD,base:SDWORD,hsize:SDWORD
  movsxd r9,r9d
  mov    r11d,r8d
  mov    rbx,rdx
  add    r9,rcx

  xor    eax,eax
  mov    r10,rcx
  mov    [rdx],rax
  mov    [rdx+8],rax
  .repeat
    movzx   rax,BYTE PTR [r10]
    .if (al <= '9')
      sub   eax,'0'
    .else
      or     eax,20h
      sub    eax,57h
    .endif
     mov    rdx,rbx
    .for (r8d=8¦r8d¦r8d--)
      movzx   ecx,WORD PTR [rdx]
      lea     rdx,QWORD PTR [rdx+2]
      imul    ecx,r11d
      add     eax,ecx
      mov     [rdx-2],ax
      shr     eax,16
    .endfor
    inc r10
  .until (r10==r9)
  ret
hatoi128 ENDP
Title: Re: atou_ex 64bit version
Post by: jj2007 on April 27, 2015, 07:49:58 PM
Quote from: rrr314159 on April 27, 2015, 07:53:37 AM
Listen to Habran, he is a doer

He's overdoing it :P

No, seriously: compliments to Habran, you are doing a great job :t
Title: Re: atou_ex 64bit version
Post by: habran on April 27, 2015, 08:13:52 PM
It's a great pleasure to receive flowers from you jj2007 :biggrin:
Title: Re: atou_ex 64bit version
Post by: Gunther on April 28, 2015, 12:46:39 AM
Hi rrr,

Quote from: rrr314159 on April 27, 2015, 07:53:37 AM
BTW Gunther's reference (Wikipedia) is incomplete and has the standard mistake re. floating point (which I've mentioned often) - seems to be required for any write-up on the net. Use MSDN for info, the only place I've seen that gets this one right

that might be, but the following sources are complete: source 1 (https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx), source 2 (https://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), source 3 (https://msdn.microsoft.com/en-us/library/dn375768.aspx). Interesting is the following overall view (http://yankeerino.com/windowsx64callingconvention.bhs), too. A drawback is that __vectorcall is not mentioned. But the comparison between Windows and Unix is interesting.

By the way, good job Habran.  :t

Gunther
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 28, 2015, 04:38:46 AM
gunther, I know MSDN has the right info somewhere, when I get around to it I'll search my notes. The Visual Studio 2013 pages you give 1) may be correct for Visual Studio for all I know, 2) may have the right info somewhere if I read all the other pages, but, the specific pages on Register Usage are wrong for MASM and our environment. They have the same old error re floating point. - and it's not trivial, you will soon run into it if you do much 64-bitting

[edit] actually, come to think of it, as long as you use invoke in the normal way you don't have to worry about it. If you write an invoke macro for ML64, as I did, then it's inescapable; or if you load up registers then call a function, expecting those ref's to be correct. But JWasm invoke does it right, so u don't really have to deal with it
Title: Re: atou_ex 64bit version
Post by: Gunther on April 30, 2015, 04:46:46 AM
Hi rrr,

Quote from: rrr314159 on April 28, 2015, 04:38:46 AM
[edit] actually, come to think of it, as long as you use invoke in the normal way you don't have to worry about it. If you write an invoke macro for ML64, as I did, then it's inescapable; or if you load up registers then call a function, expecting those ref's to be correct. But JWasm invoke does it right, so u don't really have to deal with it

all the invoke and other fancy hll stuff isn't my way. I've another point of view.

Gunther
Title: Re: atou_ex 64bit version
Post by: rrr314159 on April 30, 2015, 08:10:17 AM
Quote from: Guntherall the invoke and other fancy hll stuff isn't my way. I've another point of view.

- We're on the same page! I too want to get down to the nitty-gritty - know exactly how things work - like mabdelouahab, whose attitude I admire. Like him, if I want to know, and someone else has the answer - I ask
Title: Re: atou_ex 64bit version
Post by: Gunther on May 03, 2015, 08:57:33 PM
Quote from: rrr314159 on April 30, 2015, 08:10:17 AM
- We're on the same page! I too want to get down to the nitty-gritty - know exactly how things work - like mabdelouahab, whose attitude I admire. Like him, if I want to know, and someone else has the answer - I ask

Yes, of course. The tricky point with all that fancy macro stuff is that: Do you have the full control over the code? If not, you can do the same with HLL.

Gunther
Title: Re: atou_ex 64bit version
Post by: rrr314159 on May 04, 2015, 07:46:02 AM
Tricky macro stuff: I have to admit I don't have "full control". That would mean knowing what macros will do before trying them. No, I have to run it: don't always know whether, for instance, a nested macro argument will be expanded, or how far, until I do. When it doesn't work, I put a lot of %'s and &'s in. Since it still doesn't work, I take them out; usually then, it works ;) I honestly don't think it's entirely consistent, the rules vary according to factors only qWord understands. However I'm getting better at it .. the key thing is, once it works it keeps working; without that, forget it; but that is the case. And, macros are so powerful they're worth some hair torn out.

HLL: I finally realized, when people refer to MASM HLL they mean those .if, .else statements! I thought it meant languages like C or Pascal - and sometimes, it does - or Randall Hyde's HLA, or something. Now that I know what goes on "under the hood" I use those HLL constructs and think they're great. Habran's example convinced me ... also an old thread from a couple years ago where nidud is fixing them in JWasm and argues convincingly for his project
Title: Re: atou_ex 64bit version
Post by: habran on May 04, 2015, 02:01:59 PM
Hey rrr314159 :biggrin:
I am happy to hear that you now understand the beauty of HLL :t
Easy to read and understand what's going on
BTW did you read your PM?
Title: Re: atou_ex 64bit version
Post by: fearless on September 06, 2016, 12:26:15 PM
Just wondering if anyone has a working 64bit code version of the utoa_ex function? ive had no success converting the existing code.
Title: Re: atou_ex 64bit version
Post by: hutch-- on September 06, 2016, 01:35:18 PM
 :biggrin:

Humerously enough, I forgot how it works as I wrote it years ago but just converted it and it works OK. If you want it as a library module, just put it into a bare procedure in ML64 and assemble it. I have added the NOSTACKFRAME to turn off the prologue/epilogue code that I am using with ML64.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    LOCAL decstr :QWORD

    mrm decstr, "12345678"

    mov rcx, decstr
    call atou_ex

    conout str$(rax),lf

    waitkey

    invoke ExitProcess,0

    ret

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

NOSTACKFRAME

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

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+1]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+2]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+3]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+4]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+5]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+6]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+7]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+8]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+9]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+10]
    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

STACKFRAME

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end
Title: Re: atou_ex 64bit version
Post by: hutch-- on September 06, 2016, 01:55:13 PM
This one will do 19 digits.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

NOSTACKFRAME

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

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+1]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+2]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+3]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+4]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+5]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+6]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+7]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+8]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+9]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+10]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+11]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+12]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+13]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+14]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+15]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+16]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+17]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+18]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+19]
    test rax, rax
    jz quit

    lea r11, [r11+r11*4]
    lea r11, [rax+r11*2-48]
    movzx rax, BYTE PTR [rcx+20]
    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

STACKFRAME

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: atou_ex 64bit version
Post by: habran on September 06, 2016, 02:31:33 PM
Quote from: fearless on September 06, 2016, 12:26:15 PM
Just wondering if anyone has a working 64bit code version of the utoa_ex function? ive had no success converting the existing code.
Title: Re: atou_ex 64bit version
Post by: TWell on September 06, 2016, 05:47:11 PM
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
Title: Re: atou_ex 64bit version
Post by: habran on September 06, 2016, 06:14:39 PM
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:
Title: Re: atou_ex 64bit version
Post by: fearless on September 06, 2016, 07:03:08 PM
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.
Title: Re: atou_ex 64bit version
Post by: hutch-- on September 06, 2016, 08:40:14 PM
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.
Title: Re: atou_ex 64bit version
Post by: habran on September 07, 2016, 12:56:47 AM
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
Title: Re: atou_ex 64bit version
Post by: fearless on September 07, 2016, 06:11:54 AM
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.
Title: Re: atou_ex 64bit version
Post by: habran on September 07, 2016, 06:21:53 AM
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
Title: Re: atou_ex 64bit version
Post by: habran on September 07, 2016, 08:55:32 AM
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'

Title: Re: atou_ex 64bit version
Post by: habran on September 08, 2016, 10:27:43 AM
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

Title: Re: atou_ex 64bit version
Post by: MichaelW on September 28, 2016, 06:05:20 AM
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.