Author Topic: Printing long number  (Read 9164 times)

Offline mk8

  • Jr. Member
  • *
  • Posts: 5
Printing long number
« on: May 03, 2014, 04:53:53 PM »
Hi, this is my second topic here, I try to learn a bit of nasm, and got some new issues ;p
My goal is to print any number, so I  thought to divide by 10 number until result isn't 0, and push remainder on stack. Than I wanted to print all from stack, but I am not sure how to find out how many values I have on stack, so when I need to stop `pop` - anyway It doesn't work.

Code: [Select]
section .text
    global _start
_start:

  mov eax, 12345
  intoascii:
    cmp eax, 0
    je done

    mov ebx, 10 ; inside loop..mhm(?)
    div ebx     ; i hope result eax/abx is in eax and remainder is in edx
    push edx    ; push remainder on stack

    jmp intoascii
  done:

xor esi,esi
print:
cmp esi, 5 ; len[12345], every digit from stack
je endprint

  mov eax, 4
  mov ebx, 1
  mov ecx, 65
  pop ecx
  add ecx, 30h  ;int to ascii number
  mov [temp], ecx
  mov ecx, temp
  mov edx, 1
  int 80h
  inc esi
  jmp print

endprint:

  mov eax, 1
  mov ebx, 0
  int 80h

section .data
segment .bss
temp resb 1

May someone look, and say what should I add/change.
Thanks!

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Printing long number
« Reply #1 on: May 03, 2014, 07:25:18 PM »
Hi mk8,

You're on the right track. (one of several ways to do this) There are a couple of ways to know when to stop "pop"ing. One way would be to "push" some "guard value" first (anything but 0..9 would do) and watch for it as you "pop". An even more obvious way would be to count 'em...

There's another little issue that may be screwing you up.  "div ebx" calculates "edx:eax/ebx", not just "eax/ebx". We might want a 32-bit by 32-bit divide, but that's not what the instruction does, it's a 64-bit by 32ibit divide. This "bug" bites almost every beginner - it's almost a "rite of passage". If edx >= ebx, the quotient won't fit in eax, causing an exception that will crash your program. If you had added '0' to edx before pushing it, you might run into this. Since you add '0' later, it just gives wrong results (almost "worse", actually). We need to zero edx before the "div" every time through the loop.

Here's your code with a couple of minor changes...
Code: [Select]
section .text
    global _start
_start:

  mov eax, 12345
  xor esi, esi ; digit counter
  ; could set ebx here and leave it, too
  intoascii:
    cmp eax, 0
    je done

    mov ebx, 10 ; inside loop..mhm(?)
    ; could do it outside the loop, but this is okay
    xor edx, edx ; this needs to be inside the loop!
    div ebx     ; i hope result eax/abx is in eax and remainder is in edx
    ; close. edx:eax/ebx
    push edx    ; push remainder on stack
    inc esi ; count the digit
    jmp intoascii
  done:

; xor esi,esi
print:
 ; this would be okay if we know we've got 5 digits
;cmp esi, 5 ; len[12345], every digit from stack
;je endprint

  mov eax, 4
  mov ebx, 1
  mov ecx, 65 ; ?
  pop ecx
  add ecx, 30h  ;int to ascii number
; you're putting 4 bytes in a one-byte variable
;  mov [temp], ecx
  mov [temp], cl
  mov ecx, temp
  mov edx, 1
  int 80h
;  inc esi
;  jmp print
  dec esi
  jnz print
endprint:

  mov eax, 1
  mov ebx, 0
  int 80h

section .data
segment .bss
temp resb 1

That's untested, but I think it'll work. Don't hesitate to fiddle with it and try different things. If the number is 0, you probably want to print '0' rather than ignore it entirely. Just move the test for eax=0 a little later in the loop. An alternative to pushing/popping remainders to get 'em in the right order is to put 'em in the buffer (you'll need a buffer big enough) from the "end" and work back toward the "beginning". This may not get you all the way to the beginning before you run out of digits, so you'll need to keep track of the "print position" and the count. Or you can pad the buffer with spaces - "right justified" numbers look nice if you're printing a column of numbers, if you're printing it "in line" you probably don't want the spaces. Make it "work" first, you've got the rest of your life to make it "elegant".

(after looking again at the above code, I've got a bug in it. If esi is zero, "dec esi" is going to loop for a long time! You probably want to print at least one digit anyway. See if you can fix it.)

Best,
Frank


Offline mk8

  • Jr. Member
  • *
  • Posts: 5
Re: Printing long number
« Reply #2 on: May 03, 2014, 08:05:59 PM »
Thank you Frank for your reply, its a second one which helped me with solving problem and also give a lot of good essential content :)
« Last Edit: May 03, 2014, 08:09:09 PM by mk8 »