flat assembler
Message board for the users of flat assembler.

Index > Main > integer to string - bug?

Author
Thread Post new topic Reply to topic
kamac



Joined: 06 Dec 2013
Posts: 12
kamac 07 Dec 2013, 20:23
Hey.

I have more and more impressions that FASM is sometimes buggy? I don't know.. Maybe I am doing some thing wrong?

Can somebody see what is wrong with this code? It takes in an int and returns a string.. The problem is that when I try to iterate from beginning to end (when appending characters to the string), it works, but when I try to change direction and go from end to beginning, it just doesn't

It's hard to describe.. I suggest trying to run it yourself
:

Code:
intToStr:
        push ebp
        mov ebp,esp
        push esi
        push edi
        sub esp,12

        mov dword[ebp-4],1
        cmp dword[ebp+8],0
        jge @f
        mov dword[ebp-4],0 ; 0 - minus value, 1 - plus value
        @@:
        mov ebx,0 ; 0 digits
        mov esi,dword[ebp+8]
        mov dword[ebp-12],esi
        ; count how many digits does the int have
        @@:
        mov edx,0
        mov eax,dword[ebp+8]
        mov ecx,0Ah
        idiv ecx
        mov dword[ebp+8],eax
        add ebx,1
        cmp dword[ebp+8],0
        jne @b

        add ebx,1
        mov edi,ebx
        push ebx
        call [malloc]
        add esp,4
        mov dword[ebp-8],eax

        mov esi,dword[ebp-12]
        mov dword[ebp+8],esi
        mov ebx,0
        ;Begin filling the string with new characters that are taken from the int
        @@:
        mov edx,0
        mov eax,dword[ebp+8]
        mov ecx,0Ah
        idiv ecx
        mov dword[ebp+8],eax
        mov esi,dword[ebp-8]
        add esi,edi     ; ]
        sub esi,ebx    ; | THIS IS WHERE THE BUG STRIKES.
        sub esi,2       ; ]
        add edx,48
        mov dword[esi],edx
        add ebx,1
        cmp dword[ebp+8],0
        jne @b

        mov eax,dword[ebp-8]
        add eax,edi
        sub eax,1
        mov byte[eax],0
        mov eax,dword[ebp-8]
        mov esi,dword[ebp-12]
        mov dword[ebp+8],esi
        pop edi
        pop esi
        mov esp,ebp
        pop ebp
        ret
    



( when I input value 789 and iterate from beginning to end, I will get output: 987, when I try to switch the direction and go from end to beginning, I'll get: )7. I tried EVERY common method )
Post 07 Dec 2013, 20:23
View user's profile Send private message Reply with quote
kamac



Joined: 06 Dec 2013
Posts: 12
kamac 07 Dec 2013, 20:46
Alright, I found the problem (it lies here:
mov dword[esi],edx
Instead of assigning a byte I was assigning whole dword, which was erasing all of my latter fields)

Now, the problem is that it crashes when I do:
mov al,byte[edx]

What could be the problem?

@EDIT

It looks like FASM doesn't support such conversion? How should I do it, then?

@EDIT2

I found that it's possible to do the following:
Code:
mov eax,12
and eax,0xff
; the al register now stores 8-bit value of eax register    


Though, the and-ed register must be eax in order to set al register to it's 8-bit equivalent. Disturbing.
Post 07 Dec 2013, 20:46
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 08 Dec 2013, 13:23
May I suggest a simpler code?
It uses parameters in registers, however.
Code:
align 16
Int32ToAscii:
; ---------------------------------------------------------------------------
; INPUT:
;   EAX = value to convert to a string
;   EDI = points to a buffer of ANSI characters
;         buffer here ^^^ 12 bytes at least -- (10 digits, 'minus', terminating null)
; ---------------------------------------------------------------------------
    pusha
    ;
    ; If value is negative, revert it and store 'minus' into buffer
    ;
    xor       ecx, ecx   ; ECX=0
    add       eax, ecx   ; VALUE += 0
    jns       @f         ; If sign is not detected -- skip to dividing part
    ;
    ; VALUE is negative
    ;
    neg       eax
    mov       byte [edi], '-'
    add       edi, 1
    ;
    ; VALUE will be divided by 10, so ECX=10
    ;
@@:
    add       ecx, 10
    xor       esi, esi   ; ESI=0 -- counter of digits pushed on stack

.div_by_10:
    xor       edx, edx
    div       ecx
    ;
    ; EDX now has a remainder (a digit)
    ; EAX now has leftover from VALUE
    ;
    add       edx, '0'
    push      edx
    add       esi, 1
    ;
    ; IF (EAX not 0) -- continue dividing by 10
    ;
    test      eax, eax
    jnz       .div_by_10
    ;
    ; At this point # of digits are stored on stack
    ; and that # is in ESI. Must pop digits and store them at EDI.
    ; Because of using stack -- the digits will come into
    ; the buffer in reverse order (vs. the dividing order)
    ;
.put_digit:
    pop       eax
    stosb
    sub       esi, 1
    jnz       .put_digit
    ;
    ; Terminate string with 00h byte
    ;
    mov       [edi], ah
    popa
    ret
    
Post 08 Dec 2013, 13:23
View user's profile Send private message Send e-mail Reply with quote
tthsqe



Joined: 20 May 2009
Posts: 767
tthsqe 08 Dec 2013, 13:52
you don't need to keep track of the number of digits, just save the stack point first. This is what I use
Code:
PrintInteger:       ; rax: unsigned number
                    ; [rdi]: string result
                       push  rbp rdx rcx
                        mov  ecx,10
                        mov  rbp,rsp
                .l1:    xor  edx,edx
                        div  rcx
                       push  rdx
                       test  eax,eax
                        jnz  .l1
                .l2:    pop  rax
                        add  al,'0'
                      stosb
                        cmp  rsp,rbp
                         jb  .l2
                        pop  rcx rdx rbp
                        ret          
Post 08 Dec 2013, 13:52
View user's profile Send private message Reply with quote
kamac



Joined: 06 Dec 2013
Posts: 12
kamac 08 Dec 2013, 15:14
AsmGuru62, nice code, but I need to follow the convenction of using push to pass arguments. I'll modify it a bit to work with push instructions, if you don't mind. Also, thanks for pointing out the pusha & popa instructions Smile

I'm quite inexperienced with ASM, though, so I'll ask - is align 16 neccessary there?

Do you think that adding
mov eax,[ebp+8]
mov edi,[ebp+12]
after pusha instruction, and
mov eax,edi
before popa instruction would be sufficient changes to make it work with pushed values?

tthsqe, I appreciate the input, but I don't think long mode registers would work with architecture that supports x86 instructions only. (And this is what I aim for, at the moment)
Post 08 Dec 2013, 15:14
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 08 Dec 2013, 16:48
@kamac:
I see you are working on integrating ASM and C++ (I saw your other post Smile )
If you already using __stdcall convention, then (most likely) PUSHA/POPA will not be needed.
I would make these changes to complete the routine as __stdcall function:
Code:
;
; CALL into aligned label is faster than to un-aligned.
; This suggested in Intel manuals. Also, if you look at disassembled code
; in C/C++ -- you will see that all functions are aligned.
;
align 16
Int32ToAscii:
        ;
        ; Standard stdcall prolog
        ; EBX is not preserved -- not used
        ;
        push    ebp
        mov     ebp, esp
        push    esi edi
        ;
        ; Load parameters (assuming 1st is Int32, 2nd is ANSI buffer)
        ;
        mov     eax, [ebp + 8]
        mov     edi, [ebp + 8+4]
        ;
        ; conversion code below (PUSHA/POPA excluded)
        ;

        ...

        ;
        ; Return buffer back In EAX (string routines convention in C/C++)
        ;
        mov     eax, [ebp + 8+4]
        pop     edi esi ebp
        ret     8       <-- 2 parameters cleanup!
    
Post 08 Dec 2013, 16:48
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.