0

I wrote an Assembly program (x86_64 Linux NASM) that prints an integer to console, based in the algorithm suggested my the comments in this post, which is basically this:

divide number x by 10, giving quotient q and remainder r
emit r
if q is not zero, set x = q and repeat

All works just fine under the following script:

section .bss
        integer resb 100        ; it will hold the EOL
        intAddress resb 8       ; the offset

section .text

        global _start:

_start:

        mov rax, 567
        call _printProc

        mov rax, 60
        mov rdi, 0
        syscall


_printProc: ; here goes the algorithm described above.

After compiling it, the number 567 gets printed on the screen (console).

But if I try to do the same but allowing the user to input the number to be printed as integer I don't get what expected. Well, to do this I made the following changes (the algorithm stays the same):

section .bss
        integer resb 100        ; it will hold the EOL
        intAddress resb 8       ; the offset
        number resb 100

section .text

        global _start:

_start:

        ; getting user input
        mov rax, 0
        mov rdi, 0
        mov rsi, number
        mov rdx, 100
        syscall

        mov rax, [number]       ; passing the content at address number into rax
        call _printProc

        mov rax, 60
        mov rdi, 0
        syscall


_printProc: ; here goes the algorithm described above.

But in this case if I type 567 I get 171390517. In fact, if I type

0, I get 2608
1, I get 2609
2, I get 2610

and so on.

I'd appreciate if some of you have an idea about what is the problem in the second case and how could be fixed.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
asd
  • 1,017
  • 3
  • 15
  • 21
  • 1
    For input you need to convert from text to number (the reverse of the output conversion). For `0` input you get `2608` because your input is the ascii code of `0` which is `48` followed by a line feed with code `10`, and that gives `48+10*256=2608` in little endian. – Jester May 08 '17 at 22:41
  • @Jester So in that case I would have to subtract 48 (ASCII code for `0`) from the remainder. Is that correct? Am I missing something else? – asd May 08 '17 at 22:50
  • 1
    Yes, and for multiple digits you of course need to scale by the appropriate power of 10, and obviously ignore the line feed. You don't do this during the output, it's an input conversion there is no "remainder". – Jester May 08 '17 at 22:56
  • @Jester I'm quite new on Assembly so I'd like to get this about multiple digits correctly. From what you said I deduced that the input by the user is ''taken'' one byte (digit) at a time (maybe a somewhat stupid question. Now I'm thinking how I output the number: digit by digit). So for instance if the user input `345`, he indeed input first `51` (ASCII for `3`) then `52` and finally `53`. So at memory `intAddress` I hold the `51`, at `intAddress + 1` we have `52` and `intAddress + 3` the `53`. (my comment is too long so I write below as well). – asd May 08 '17 at 23:14
  • @Jester If that is the case, How do you suggest to keep track of the offset in order to know how many time I have to scale by `10` (since I won't know how many digit the user input till he hits `Enter`)? – asd May 08 '17 at 23:14
  • 2
    The usual trick is to multiply the working value by 10 then add the new digit. Repeat as long as you have digits. E.g. you will have `((51-48)*10+(52-48))*10+(53-48)` – Jester May 08 '17 at 23:18

1 Answers1

1

what happends when you call this

    ; getting user input
    mov rax, 0
    mov rdi, 0
    mov rsi, number
    mov rdx, 100
    syscall

is, that your entry ( e.g. "1004") is written to the memory at "number", character per character. Now you have the exact opposite problem you intended to solve: "how to convert an ASCII string into binary value"

the algorithm for this new problem could look like this:

(assuming char_ptr points to the string)
result = 0;
while ( *char_ptr is a digit )
    result *= 10;
    result += *char_ptr - '0' ;
    char_ptr++;
Tommylee2k
  • 2,683
  • 1
  • 9
  • 22