Author Topic: converting integer to string through iteration  (Read 16810 times)

Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
converting integer to string through iteration
« on: July 02, 2014, 05:35:52 AM »
I have the following code

Code: [Select]

segment .data
  counter dd 3024
 
segment .bss
  buffer resb 4
 
segment .text
  global _start

  _start:

  mov ecx, counter
 
  l1:
    push ecx
   
    dec dword [counter]
    lea esi, [counter]
    call int_to_string
   
    mov [buffer], eax
   
    mov eax, 4
    mov ebx, 1
    mov ecx, buffer
    mov edx, 4
    int 0x80
   
    pop ecx
  loop l1

  mov eax, 1
  mov ebx, 0
  int 0x80
 
 
int_to_string:
  add esi, 9
  mov byte [esi], 10
  mov ebx, 10         

.next_digit:
  xor edx, edx       
  div ebx             
  add dl, '0'         
  dec esi             
  mov [esi],dl
  test eax, eax           
  jnz .next_digit
  mov eax, esi
  ret


As you see, I just try to count from 3024 to zero, converting the counter to string and output it on the screen. I've tried many things with no luck. Can you please show me some direction on what I can do?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: converting integer to string through iteration
« Reply #1 on: July 02, 2014, 06:31:14 AM »
I think your main problem was that you confused "counter" and "buffer". You were trying to convert the number to text, and put the text in [counter]. I need sleep, so this is sloppy, but I think you'll find it closer...
Code: [Select]

segment .data
  counter dd 3024
 
segment .bss
  buffer resb  12 ; 4
 
segment .text
  global _start

  _start:

  mov ecx, [counter]
 
  l1:
    push ecx
   
    dec dword [counter]
;    lea esi, [counter]
    lea esi, [buffer]
    mov eax, [counter]
    call int_to_string
   
;    mov [buffer], eax

    mov ecx, eax ; "begin print" position
    xor edx, edx
getlen:
    cmp byte [ecx + edx], 10
    jz gotlen
    inc edx
    jmp getlen
gotlen:
    inc edx
   
    mov eax, 4
    mov ebx, 1
;    mov ecx, buffer
;    mov edx, 10
    int 0x80
   
    pop ecx
  loop l1

  mov eax, 1
  mov ebx, 0
  int 0x80
 
 
int_to_string:
  add esi, 9 ; counter + 9 ?
  mov byte [esi], 10
  mov ebx, 10         

.next_digit:
  xor edx, edx       
  div ebx             
  add dl, '0'         
  dec esi             
  mov [esi],dl
  test eax, eax           
  jnz .next_digit
  mov eax, esi
  ret

Maybe a better attempt later... or maybe I should let you do it...

Best,
Frank



Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
Re: converting integer to string through iteration
« Reply #2 on: July 02, 2014, 07:32:14 AM »
Thanks, the code works well now. My only problem left is the loop goes to infinity. It prints from counter to 0. After that, it first prints 4294967295 than prints 889192446 and continues to decrement from there. (889192445, 889192444 ...) As far as I know, if ECX is zero, the loop is terminated. Why is this happening?

EDIT:
If I directly write
Code: [Select]
mov ecx, 4
Instead of
Code: [Select]
mov ecx, counter
it works.

EDIT 2:
I resolved the issue by changing assignment to ecx to:
Code: [Select]
mov ecx, [counter]
Thanks, you've been a great help. For further questions, (e.g assigning this values to an array) should I open a new thread or continue within this one?
« Last Edit: July 02, 2014, 08:26:20 AM by muratohyes »

Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
Re: converting integer to string through iteration
« Reply #3 on: July 02, 2014, 01:56:13 PM »
I'm trying to fill the array with the strings I have just converted from integers. Here's my code

Code: [Select]


segment .data
  counter dd 9877
  count dd 8642
  array times 9876 dd '0000'
  pointer dd 0
 
segment .bss
  buffer resb  4 ; 4
 
segment .text
  global _start

  _start:

  mov ecx, [count]
 
  mov edx, array
  mov dword [pointer], array
 
  l1:
    push ecx
    push edx
   
    dec dword [counter]                      ; decrease the counter
    lea esi, [buffer]
    mov eax, [counter]
    call int_to_string
   
    mov ecx, eax ; "begin print" position
    xor edx, edx
getlen:
    cmp byte [ecx + edx], 10
    jz gotlen
    inc edx
    jmp getlen
gotlen:
    inc edx
   
    push eax                             ; printing the string converted
    mov eax, 4
    mov ebx, 1
    int 0x80
    pop eax                              ; printing the string converted
   
   
    ; copying the string to array
   
    pop edx
    mov [edx], eax
    add edx, 4
   
    pop ecx
  loop l1

 
  mov ecx, [count]                  ;printing the array
  mov eax, array
  l2:
    push ecx
   
    mov [pointer], eax
    push eax
   
    mov eax, 4
    mov ebx, 1
    mov ecx, pointer
    mov edx, 4
    int 0x80
   
    pop eax
    add eax, 4
   
    pop ecx
  loop l2
 
  mov eax, 1
  mov ebx, 0
  int 0x80
 
int_to_string:
  add esi, 9 ; counter + 9 ?
  mov byte [esi], 10
  mov ebx, 10         

.next_digit:
  xor edx, edx       
  div ebx             
  add dl, '0'         
  dec esi             
  mov [esi],dl
  test eax, eax           
  jnz .next_digit
  mov eax, esi
  ret


This prints random chars when I'm printing the array. Can you tell me where I'm wrong?
« Last Edit: July 02, 2014, 02:41:11 PM by muratohyes »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: converting integer to string through iteration
« Reply #4 on: July 02, 2014, 06:21:36 PM »
Well... I think I may see where you're going wrong... maybe...
Code: [Select]
; okay up to here?

    ; copying the string to array
   
    pop edx
    mov [edx], eax
    add edx, 4

As I understand it, your "int_to_string" returns what I'm calling the "start print position" - an address in "buffer" (actually outside of "buffer" - your buffer is too small - the "add esi, 9" puts us outside of "buffer". Since there's nothing after "buffer", I don't think this is a problem at present, but it isn't really "right".) Since "int_to_string" uses the same buffer for each number it converts, the same address is being stored multiple times into "array". When you try to print "array", you're printing this number - not converted to text. This is where the "garbage characters" are coming from. I think...

I think I see what's wrong, but my "quickie" attempts to fix it have been a total failure so far. Either I'm completely off-base, didn't get enough sleep, too hot to program... perhaps all of the above.

There's nothing wrong with making an "array of pointers to strings", but you have to "dereference" it properly. You might want to have two arrays, actually - one big blob of strings and an array of pointers to strings representing individual numbers. Instead of "int_to_string" getting the address of "buffer" each time, each number could be converted to a separate address in "bigbuff" - a malloced or "fake malloc" for now - address, and those addresses stored in "ptrarray". Maybe?

Keep in mind that "int_to_string" is producing a linefeed-terminated "string", and not at the "beginning" of the address that's been passed to it, but a few bytes in. There are different ways of dealing with the fact that we get the remainders in the "wrong" order. You might want to consider converting all the numbers into a "common" buffer, and copying them to their final position. This might be a good place for your "sieve" routine that eliminates duplicate digits and zeros to fit in.

Just some thoughts... probably not worth much at the moment. The research continues...

Best,
Frank


Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
Re: converting integer to string through iteration
« Reply #5 on: July 03, 2014, 10:14:49 AM »
Thanks for ideas. I will just print zeroes to "same character/zero  containing" strings, because after this operation there will be other eliminations too.

This should be printing the 4 digit numbers which doesn't contain any zeroes. It prints the first one (9876) correctly, but after that random numbers are printed out. I must be doing some pointer mistake again. Can you tell me where?

Code: [Select]
  mov ecx, [count]                  ;printing the array
  mov eax, array
  l2:
    push ecx
    mov [pointer], eax

    mov cl, 0
    digit_control:

      add cl, 1
      cmp cl, 5
      je non_zero

      mov al, byte [pointer]
      cmp al, '0'
      je zero

      add dword[pointer], 1

    jmp digit_control         

    non_zero:

    sub dword [pointer], 4

    push eax

    mov eax, 4
    mov ebx, 1
    mov ecx, [pointer]
    mov edx, 4
    int 0x80

    pop eax

    zero:

    add eax, 4
    pop ecx
  loop l2


I later tried this but no luck, prints random characters again.

Code: [Select]

      mov ecx, [count]                  ;printing the array
      mov eax, array
      l2:
push ecx
mov [pointer], eax

mov ecx, 4
mov edi, pointer
mov al, '0'
cld
repne scasb
je zero


push eax
mov eax, 4
mov ebx, 1
mov ecx, [pointer]
mov edx, 4
int 0x80
pop eax
     
      zero:
     
add eax, 4
pop ecx
      loop l2
« Last Edit: July 03, 2014, 03:01:45 PM by muratohyes »

Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
Re: converting integer to string through iteration
« Reply #6 on: July 04, 2014, 07:43:52 AM »
Pushing eax before and after the zero finding solved the problem. It surely plays with eax even it doesn't seem so with the raw code.

Code: [Select]
mov ecx, [count]                  ;printing the array
      mov eax, array
      l2:
push ecx
mov [pointer], eax
push eax

mov ecx, 4
mov edi, [pointer]
mov al, '0'
cld
repne scasb
je zero


push eax
mov eax, 4
mov ebx, 1
mov ecx, [pointer]
mov edx, 4
int 0x80
pop eax

      zero:
pop eax
add eax, 4
pop ecx
      loop l2

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: converting integer to string through iteration
« Reply #7 on: July 04, 2014, 10:07:46 AM »
Sorry... I had almost finished a reply when the power went out (just a thunderstorm, not the hurricane). I said some words I'm not allowed to say on the forum. When that happens, I'm too annoyed to repost right away... so I'm glad you got it working.

That was one of the things I spotted. When you alter al for the scasb, that alters eax so it doesn't point to the right place in "array". The other thing was a possible "dereferencing a pointer" problem. If it works now, perhaps that wasn't a problem at all.

If I understand it right, this "test version" works with four digits,  but in the "final version" you're going to let the user choose the number of digits (I hope you're not gonna let 'em choose too many!). You might want to make that a variable now, instead of hard-coding in 4. Like for ecx for scasb, edx for sys_write... maybe "add eax, [number_of_digits]" to get to the next place in "array". Just a thought. You're doing good! We spoke of possible using a linked list to store these numbers. You still interested in that?

Best,
Frank


Offline muratohyes

  • Jr. Member
  • *
  • Posts: 17
Re: converting integer to string through iteration
« Reply #8 on: July 04, 2014, 12:56:23 PM »
I can't thank you enough for your effort lately. I'm still having trouble on basics.

I must say I never wrote low-level code before, I even wrote C for only 2 months. I was a database administrative, specification taking, web services and forms coding guy. I've met with assembly 1 week ago, but it's a delight! After I got the basics right, I hope to help others here :) For now, I'm just trying to write the code in a static-fashion and make it work. After that I will start coding the dynamic allocations and variables, this is just a test-ride.