Author Topic: Converting from ASCII to Integer  (Read 20255 times)

Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Converting from ASCII to Integer
« on: June 11, 2014, 06:31:40 PM »
I have been trying to write a program that takes in a value and divides it by 16 and prints out the result, I soon found out that I needed to convert from ascii to integer to actually use the input value and with a 64 bit value I needed to iterate through each byte and subtract 48 or 0x30 in hex and so I did and then I went ahead and multiplied it by 10 each time it went through the loop and divided it by 10 at the very end to correct the error that the loop multipled too many times by 10 and I still do not get the desired result I am sorry if this might seem like a stupid question I am very new to assembly and just started a couple days ago. here is my code:

Code: [Select]
section .bss
n_number resb 255
section .data
newLine : db "",10
newLine_L : equ $ - newLine
section .text
atoi:
mov rbx, 10
mov qword [n_number], rax
mov rdi, 0


.NxtDgt:
cmp byte [n_number+rdi], 0
je next

sub byte [n_number +rdi], 0x30
mov rax, qword[n_number]


mul rbx
mov qword[n_number], rax

inc rdi
jmp .NxtDgt
next:
mov rax, qword[n_number]
mov rdx, 0
mov rcx, 10
div rcx

mov rdx, 0
mov rcx, 16
div rcx



mov rbx, 10
mov qword [n_number], rax
mov rdi, 0


.NxtDgt2:
cmp byte [n_number+rdi], 0
je next2

add byte [n_number +rdi], 0x30
mov rax, qword[n_number]


div rbx
mov qword[n_number], rax

inc rdi
jmp .NxtDgt2
next2:
mov rax, qword [n_number]
mov rdx, 0
mov rcx, 10
mul rcx

mov qword[n_number], rax

done:

mov     rdx, 255 ;length
mov     rsi, n_number;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall




mov     rdx, newLine_L;length
mov     rsi, newLine;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall

ret





« Last Edit: June 11, 2014, 06:41:05 PM by Frank Kotler »
Thanks in advance, Anonymous

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #1 on: June 11, 2014, 08:18:31 PM »
My 64-bit machine died, so I'm back to 32-bits... so I can't test this or provide a tested version. It's not a stupid question. You seem to have the general idea right, but I don't think some of the details are going to work.
Code: [Select]
section .bss
n_number resb 255
section .data
newLine : db "",10
newLine_L : equ $ - newLine
section .text
atoi:
mov rbx, 10
mov qword [n_number], rax
mov rdi, 0


.NxtDgt:
cmp byte [n_number+rdi], 0
je next
I guess you're calling this with the address of the ASCII string in rax? (and I take it it's zero-terminated) You put the address of the string in [n_number]. What we would like to do to get to the next digit is:
Code: [Select]
cmp byte [ [n_number] + rdi], 0
... but there's no such instruction. What I think I would do is put the address of the string in some register, and just use that. rdi would do (rsi might be more conventional). I think I'd get the byte from the string into a register and do my comparisons and manipulation there.
Code: [Select]
atoi:
    mov rdi, rax ; if you wish to pass the parameter in rax
    mov rbx, 10 ; to multiply by
    xor rax, rax ; to use as "result so far"
    xor rcx, rcx ; our character/digit (high bits zero)
.top:
    mov cl, [rdi] ; get a character
    add rdi, 1  ; get ready for the next one
    cmp cl, 0 ; end of string?
    je .done
    cmp cl, '0'
    jb .invalid
    cmp cl, '9'
    ja .invalid
    sub cl, '0' ; or 48 or 30h
; now that we know we have a valid digit...
; multiply "result so far" by 10
    mul rbx
    jc .overflow ; ?
; and add in the new digit
    add rax, rcx
    jmp .top
; I'm not going to do anything different for overflow or invalid
; just return what we've got
.overflow:
.invalid:
.done:
    ret ; number is in rax

I think you'll find - if I haven't screwed it up (untested code!) - that this eliminates having to divide 'cause you multiplied too many times.

One last nit...
Code: [Select]
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall

ret
... you've got the comments backwards.

Best,
Frank


Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Re: Converting from ASCII to Integer
« Reply #2 on: June 11, 2014, 09:12:48 PM »
Thank you I now get the logic but as you feared the code does not work and it seems like it should. It is giving me a seg fault
« Last Edit: June 11, 2014, 10:56:02 PM by Anonymous »
Thanks in advance, Anonymous

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #3 on: June 11, 2014, 11:11:56 PM »
Hmmm... Do I understand correctly that you're passing the address of the string in rax? What's the caller look like? I should probably have "global atoi" in there...

Best,
Frank


Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Re: Converting from ASCII to Integer
« Reply #4 on: June 12, 2014, 01:07:23 AM »
EDIT here is the new code turns out I was just calling it wrong:
Code: [Select]
;------------------------------------------
; int atoi(Integer number)
; Ascii to integer function (atoi)

;%include "functions.asm"

section .data

MSG: db "Input number : ",10
MSG_L: equ $ - MSG
section .bss
x_number resb 255
section .text
global _start:

_start:

mov     rdx, MSG_L ;length
mov     rsi, MSG;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall


mov     rdx, 255
mov     rsi, x_number
mov     rdi, 0
mov     rax, 0
syscall



mov     rdi, x_number
call    atoi 

mov rdx, 0
mov rcx, 16
div rcx

mov rdi, [rax]

call itoa

mov rdi, 255
mov rsi, rax
mov rdi, 1
mov rax, 1
syscall

mov rax, 60
mov rdi, 0
syscall
ret


atoi:
    push     rbx;if you are going to use rbx you must preserve it by pushing it onto the stack
   
    ;~ Address is passed in rdi
    mov     rbx, 10 ; to multiply by
    xor     rax, rax; to use as "result so far"
    xor     rcx, rcx ; our character/digit (high bits zero)

.top:
    mov     cl, byte [rdi] ; get a character
    add     rdi, 1  ; get ready for the next one
    cmp     cl, 0 ; end of string?
    je      .done
    cmp     cl, '0'
    jb      .invalid
    cmp     cl, '9'
    ja      .invalid
    sub     cl, '0' ; or 48 or 30h
    ; now that we know we have a valid digit...
    ; multiply "result so far" by 10
    mul     rbx
    jc      .overflow ; ?
    ; and add in the new digit
    add     rax, rcx
    jmp     .top
    ; I'm not going to do anything different for overflow or invalid
    ; just return what we've got
.overflow:
.invalid:
.done:
    pop     rbx;restore rbx to its original value
    ret ; number is in rax 
    Now I have another question how would one go about Converting from integer to ASCII so I can print out the result I haven't at all looked at what algorithm to use so I have no idea how to do this I have tried doing the inverse of atoi by adding 48 and dividing by 10 instead of the other way around and it didn't work. Also how do I make code blocks in this forum?
   
   
« Last Edit: June 12, 2014, 02:05:31 PM by Anonymous »
Thanks in advance, Anonymous

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #5 on: June 12, 2014, 09:12:36 AM »
Code blocks are easy. Just the word "code" in square brackets (like a Nasm memory reference) at the top, and "/code" in square brackets at the end. This might make it easier to read, and definitely makes it easier to cut and paste.

You've got the right idea for itoa. Divide by ten, then add '0' (48 or 30h) to the remainder (in rdx). Unfortunately, we get these remainders in the opposite order from which we're going to want to print them. There are different ways to deal with this. You could just put 'em in the buffer "backwards" and then do a "string reverse" on it. You could push 'em on the stack and then pop 'em off in the "right" order. This is what I usually show beginners, since I think it's easier to understand. Maybe it is and maybe it isn't. Or, you could put 'em in the buffer starting at the "end" and working towards the "front". You'll probably run out of digits (indicated by rax being zero) before you get all the way to the start of the buffer, so keep track of the "start position" to tell sys_write... or space-pad (or zero-pad) the buffer to the beginning. Right justified numbers look nicer (IMO) if you're going to print them in a column. You'll need to tell sys_write how many characters to print, of course.

I may be able to come up with an example (later), but give it a shot.

Best,
Frank


Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Re: Converting from ASCII to Integer
« Reply #6 on: June 12, 2014, 03:58:53 PM »
I tried it and I think this should work but I think I am calling it wrong I have no Idea where my error is . Here is my code :

Code: [Select]
;------------------------------------------
; int atoi(Integer number)
; Ascii to integer function (atoi)

;%include "functions.asm"

section .data

MSG: db "Input number : ",10
MSG_L: equ $ - MSG
section .bss
x_number resb 255
section .text
global _start:

_start:

mov     rdx, MSG_L ;length
mov     rsi, MSG;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall


mov     rdx, 255
mov     rsi, x_number
mov     rdi, 0
mov     rax, 0
syscall



mov     rdi, x_number
call    atoi 

mov rdx, 0
mov rcx, 16
div rcx
mov qword [x_number], rax
mov rdi, x_number

call itoa

mov rax, 60
mov rdi, 0
syscall
ret


atoi:
    push     rbx;if you are going to use rbx you must preserve it by pushing it onto the stack
   
    ;~ Address is passed in rdi
    mov     rbx, 10 ; to multiply by
    xor     rax, rax; to use as "result so far"
    xor     rcx, rcx ; our character/digit (high bits zero)

.top:
    mov     cl, byte [rdi] ; get a character
    add     rdi, 1  ; get ready for the next one
    cmp     cl, 0 ; end of string?
    je      .done
    cmp     cl, '0'
    jb      .invalid
    cmp     cl, '9'
    ja      .invalid
    sub     cl, '0' ; or 48 or 30h
    ; now that we know we have a valid digit...
    ; multiply "result so far" by 10
    mul     rbx
    jc      .overflow ; ?
    ; and add in the new digit
    add     rax, rcx
    jmp     .top
    ; I'm not going to do anything different for overflow or invalid
    ; just return what we've got
.overflow:
.invalid:
.done:
    pop     rbx;restore rbx to its original value
    ret ; number is in rax 
   
   
   
   
    itoa:
   
push rbx

mov rbx, 10
        ;puts a zero before everything so that in the next loop it will know when to stop
dec rdi
mov byte [rdi], 0
inc rdi
.top:;loops through to the end so that rdi points to the end

mov cl, byte [rdi]

inc rdi

cmp rdi, 0
je .next

jmp .top

xor rax, rax;clears out rax just in case
xor rdx, rdx;clearing out rdx just incase


.next:
mov al, byte [rdi];moves the next character into al

div rbx;divide by ten
add rdx, '0';convert to ASCII

mov     rdx, 1 ;length
mov     rsi, rdx;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall


cmp byte [rdi], 0;is it the end?
je .done;f so jup to done
dec rdi;get ready for the next character
jmp .next



    .done:
pop rbx
    ret
   

It is seg faulting , looks like I cause a lot of those lol
Thanks in advance, Anonymous

Offline Gunner

  • Jr. Member
  • *
  • Posts: 74
  • Country: us
    • Gunners Software
Re: Converting from ASCII to Integer
« Reply #7 on: June 13, 2014, 02:23:14 AM »
Is this your first foray into Assembly language?  Do you know a high level language such as C?  You haven't read the Linux 64 bit /SYSTEM V/ AMD64 ABI have you?  (Google it)  The 64 bit ABI is MUCH different than the 32 bit ABI!  The AMD64 ABI is MUCH different than the Windows 64 bit ABI (Notice I am using ABI and NOT API, which is different)  The ABI is a set of rules that dictate when what registers need to be saved across a function call, which don't need to be saved, stack alignment, return values etc...  It would behoove you to read it!!!  Unlike the 32 bit ABI; rdi and rsi are volatile registers, meaning their value does not have to be preserved across calls.

In your itoa call, you have the address of a string in rdi, you then make a system call in your loop which then trashes the value (address) in rdi!  At the start of your function, you should move the address that is in rdi into a non-volatile register r12 - r15, and of course, save the register at the start and restore it at the end of the proc.

Code: [Select]
add rdx, '0';convert to ASCII

mov     rdx, 1 ;length
mov     rsi, rdx;variable
mov     rdi,1;sys_write
mov     rax, 1;stdout
syscall
Your converting to ASCII and trying to print a character with a syscall, they do not work like this, they need an address of a char or string.  Easiest way is to put this char into a local var (think rsp) and pass the address of rsp to the syscall.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #8 on: June 13, 2014, 10:46:30 AM »
Hi Gunner,

Yeah, he says right up top he's only been at it for a few days. I think he's doing pretty well, but there are a few problems...
Code: [Select]
add rdx, '0';convert to ASCII
; so now we've got a character ready to print
; so we overwrite it with 1...
mov     rdx, 1 ;length
; and then tell rsi that it's our address of buffer...
mov     rsi, rdx;variable
; rdi is stdout (our file descriptor/handle)
mov     rdi,1;sys_write
; rax is sys_write
mov     rax, 1;stdout
; I know you knew that. :)
syscall

I have read the ABI (Application Binary Interface) - a long time ago. I've apparently forgotten a lot. I'll have to "use" it before I "get" it, anyway. They trash rsi and rdi? That's really rude!

But we may not be ready for a system call quite yet. Printing the characters one at a time at this point will get 'em backwards anyway.

Let's poke at this. I think you're okay up to here...
Code: [Select]
mov     rdi, x_number
call    atoi 
; if this works as promised, our number is in rax
mov rdx, 0
mov rcx, 16
div rcx
; remainder is in rdx, which is discarded
; I guess that's okay...

; itoa needs two parameters, at least
; the number, and a buffer to put the text in
; you cleverly pass the number in the buffer
; neat trick!
mov qword [x_number], rax
mov rdi, x_number

call itoa
; [snip]

    itoa:
   
push rbx

mov rbx, 10
    mov rax, [rdi] ; do this now

        ;puts a zero before everything so that in the next loop it will know when to stop
dec rdi
mov byte [rdi], 0
inc rdi
; you've put a zero BEFORE the buffer!

.top:;loops through to the end so that rdi points to the end

mov cl, byte [rdi]

inc rdi

cmp rdi, 0
je .next

jmp .top
; I guess this is to find the end of the buffer?
; but the buffer holds... I guess it still holds
; our text input (after our number).
; this might just work!

; xor rax, rax;clears out rax just in case
; don't do this! rax has our number

xor rdx, rdx;clearing out rdx just incase
; shouldn't be needed here

.next:

; what we want here is the whole number in rax
; not just a "character"
; mov al, byte [rdi];moves the next character into al
; mov rax, [rdi]
; but we wanted to do this while rdi pointed to it!
; we do not want to reload rax in our "div" loop

; we do need to clear rdx here
        xor rdx, rdx

div rbx;divide by ten
add rdx, '0';convert to ASCII
; now we want to put it in our buffer...
    mov [rdi], dl
    sub rdi, 1
; (I'm used to using inc and dec, but in
; long mode (64-bit) the short encodings
; are used for the "rex prefix" I believe.

; not yet...
; mov     rdx, 1 ;length
; mov     rsi, rdx;variable
; mov     rdi,1;sys_write
; mov     rax, 1;stdout
; syscall

; what tells us we're done is rax!
; cmp byte [rdi], 0;is it the end?

    test rax, rax ; or cmp rax, 0
    jne .next

; je .done;f so jup to done
; dec rdi;get ready for the next character
; jmp .next



    .done:
pop rbx
    ret
We probably need to return something intelligent here. rdi points a byte before where we're going to want sys_write to start (maybe it would have been better to decrement it later as you did), and sys_write is going to need the length - it will NOT stop on a zero-terminated string. We can calculate the length of a zero-terminated string (have to be careful to zero-terminate the string and not pre-zero it :) ). Or... we could count characters and return two values. Not compatible with any calling convention I know of, but we can do it. Works great, but probably not a good idea. :(

Or we could rename the function from "itoa" to "print_int", put the sys_write back into it, and not return anything. Since we're not dealing with the complexities of a minus sign yet, they should be named "utoa" and "atou" anyway...

Best,
Frank


   


Offline Gunner

  • Jr. Member
  • *
  • Posts: 74
  • Country: us
    • Gunners Software
Re: Converting from ASCII to Integer
« Reply #9 on: June 14, 2014, 04:23:43 AM »
Yup Frank!

Windows 64:
Volatile: rax, rcx, rdx, r8-r11
Non-Volatile: rbx, rsi, rdi, rbp, r12-r15

Linux 64:
Volatile: rax, rcx, rdx, rsi, rdi, r8-r11
Non-Volatile: rbx, rbp, r12-r15

http://www.agner.org/optimize/calling_conventions.pdf

Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Re: Converting from ASCII to Integer
« Reply #10 on: June 15, 2014, 08:53:34 PM »
Hi Frank , I was poking around at the code you posted and when I ran it initially I got a seg fault still but as a I hacked at it in my attempt to understand I found this block of code,
Code: [Select]
.top:;loops through to the end so that rdi points to the end
;mov al, byte[rdi] this somehow was causing a seg fault
inc rdi

cmp rdi, 0
je .next

jmp .top
but once I took it out it seemed like it was in an infinite loop which wouldn't end the program I am still looking at it to figure it out perhaps you could shed some light on this. Also Gunner yes I do know some higher level languages C and java this is my first time doing assembly and I need to go reed the ABI thanks for the tip.
« Last Edit: June 15, 2014, 11:05:04 PM by Anonymous »
Thanks in advance, Anonymous

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #11 on: June 16, 2014, 07:59:22 AM »
Araaagh! Did I write that? No, no, no. That's what comes of posting untested code! :(

Code: [Select]
.top:;loops through to the end so that rdi points to the end
;mov al, byte[rdi] this somehow was causing a seg fault
inc rdi

cmp rdi, 0
; Yikes! That won't be true for a long, long time!
; I must have meant:
                cmp al, 0
je .next

jmp .top

Apparently... the fantasy was that we had a zero-terminated string in a buffer pointed to by rdi. (the text representation of the number we input) This probably was not true in the first place. sys_read does not return a zero-terminated string(!). We can zero-terminate it easily enough...
Code: [Select]
mov rdx, max_length
mov rsi, buffer
mov rdi, file_descriptor ; probably stdin
mov rax, sys_read
syscall
; at this point, rax is number of bytes actually read
; including the linefeed which terminates input
; but wait! it could indicate an error
; probably not, reading from stdin
; but we should check!
; (this is a sloppy way, but close enough)
test rax, rax
js error ; if it's negative, get out!
; okay, if we get here, rax is number read
; overwrite the linefeed with a zero
mov byte [rsi + rax - 1], 0

That may not even work. The 32-bit equivalent does, but if they're going to trash rsi on me... I may not know how to do this!

Even if we had a zero-terminated string, the length of the (text representation) number we input may not be the same as the length of the number (text representation) we wish to display. We divided by 16, so it won't be. ("shr rax, 4" would be a quicker way to divide by 16, but that isn't the point) Forget about that section of code entirely!

I know, off the top of my head, how many digits might be in a 32-bit number - 10. I know I need to have a byte for the zero terminator (if I want one), and I might want a minus sign (when we get to that), so 12 bytes. I usually reserve 16, just because it's a "nice round number". I'm going to have to count how many digits in 64-bits (text representation) (could do it with logarithms, but I forget how). Fortunately, the "extras" required should be the same.

I've seen code (from Randy Hyde) which actually does an entire separate divide loop just to find out how many characters we're going to have. This has always seemed horribly inefficient to me, but it's one way to do it.

If we push remainders as we get 'em, and count 'em, we can put 'em in the buffer starting from the "front" as we pop 'em off. This isn't very efficient either.

Starting at the "back" of the buffer and working towards the "front" is probably the way to go, but that "problem snippit" isn't a good way to find the "back" of the buffer. I'd add some arbitrary amount to rdi - since you've got a 256 byte buffer, 80 should be plenty - and work from there.

I can print a 64-bit number on this 32-bit machine, but I've gotta get that 64-bit machine back in service. Not right now...

Best,
Frank


Offline Gunner

  • Jr. Member
  • *
  • Posts: 74
  • Country: us
    • Gunners Software
Re: Converting from ASCII to Integer
« Reply #12 on: June 17, 2014, 01:27:18 AM »
The have "borrowed" code from: http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s modified it into INTEL syntax, made it handle signed numbers, and added an errno variable since I use this in a shared library.  You can take out/ignore the errno2

Code: [Select]
;~ #########################################
;~ atodw64 - Convert a string into a binary interger
;~ in      rdi - address of string to convert
;~ out     rax - converted number

;~ #########################################
atodw64:
    push    rbx

    mov     qword [errno2], 0
   
    xor     eax, eax       
    mov     rbx, 10

    xor     rsi, rsi
.CheckSign:
    mov     cl, [rdi]
    cmp     cl, "-"
    jne     .NxtDgt
    mov     rsi, 1
    inc     rdi
   
.NxtDgt:
    mov     cl, [rdi]
    test    cl, cl
    je      .StringEnd
   
    cmp     cl, "0"
    jb      .invdgt

    cmp     cl, "9"
    ja      .invdgt
   
    mul     rbx
    jc      .invdgt
    and     rcx, 0x0F 
    add     rax, rcx
    test    rax, rax
   
    inc     rdi         
    jmp     .NxtDgt 

.StringEnd:
    test    rsi, rsi
    jz      .Done
    neg     rax
.Done:
    pop     rbx
    ret
   
.invdgt:
    xor     rax, rax
    not     rax
    mov     qword [errno2], ERANGE
    pop     rbx
    ret

Offline Anonymous

  • Jr. Member
  • *
  • Posts: 78
  • Country: us
Re: Converting from ASCII to Integer
« Reply #13 on: June 17, 2014, 05:40:01 AM »
I have modified my code to use a general purpose register instead of rdi and I have changed it so now it wont seg fault and am attempting to print out the characters now but nothing is printing out at all Here is my code
Code: [Select]

 itoa:
   
push rbx

mov rbx, 10
mov rax, [r8] ; do this now

        ;puts a zero before everything so that in the next loop it will know when to stop
dec r8
mov byte [r8], 0
inc r8
; you've put a zero BEFORE the buffer!

.top:;loops through to the end so that rdi points to the end
mov al, byte[r8] ;this somehow was causing a seg fault
inc r8

cmp al, 0
je .next

jmp .top
; I guess this is to find the end of the buffer?
; but the buffer holds... I guess it still holds
; our text input (after our number).
; this might just work!

; xor rax, rax;clears out rax just in case
; don't do this! rax has our number

xor rdx, rdx;clearing out rdx just incase
; shouldn't be needed here

.next:
; what we want here is the whole number in rax
; not just a "character"
; mov al, byte [rdi];moves the next character into al
; mov rax, [rdi]
; but we wanted to do this while rdi pointed to it!
; we do not want to reload rax in our "div" loop

; we do need to clear rdx here
xor rdx, rdx

div rbx;divide by ten
test rax, rax ; or cmp rax, 0
jne .next

add rdx, '0';convert to ASCII
; now we want to put it in our buffer...
mov byte [r8], dl
mov qword[x_number],rax
call print
mov rax, qword[x_number]
sub r8, 1
; (I'm used to using inc and dec, but in
; long mode (64-bit) the short encodings
; are used for the "rex prefix" I believe.

; not yet...
; mov     rdx, 1 ;length
; mov     rsi, rdx;variable
; mov     rdi,1;sys_write
; mov     rax, 1;stdout
; syscall

; what tells us we're done is rax!
; cmp byte [rdi], 0;is it the end?
; je .done;f so jup to done
; dec rdi;get ready for the next character
; jmp .next

    .done:
pop rbx
    ret
   
   
    print:
;I think this is where I am going wrong any ideas?
mov     rdx, 255
mov rsi, qword [r8]
mov     rdi,1
mov     rax, 1
syscall

    ret




Thanks in advance, Anonymous

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting from ASCII to Integer
« Reply #14 on: June 17, 2014, 01:53:45 PM »
Dangerous to be flailing around blindly like this, but "fools rush in...".

Code: [Select]
itoa:
; expects: buffer in r8
; number to convert in buffer (unusual, but should work)
;
; returns: "start print" position in rax
; zero-terminated string in buffer
; miscellaneous registers trashed

push rbx

mov rbx, 10
mov rax, [r8] ; our number was in buffer
        add r8, 80 ; this is "too much", but should work
        mov byte [r8], 0 ; we want a zero-terminated string, right?
        sub r8, 1

.next:
; we do need to clear rdx here - "div" uses it
xor rdx, rdx

div rbx;divide by ten
; quotient in rax, remainder in rdx

add rdx, '0';convert to ASCII
; now we want to put it in our buffer...
mov byte [r8], dl

call print ; for every digit? okay...

                test rax, rax ; or cmp rax, 0
                jz .done

sub r8, 1
                jmp .top
.done:
; return "start print" position in rax
        mov rax, r8
pop rbx
        ret
;-----------------   

;-------------------
    print:
;I think this is where I am going wrong any ideas?
; yeah...
; we're trashing registers we were using
; save 'em
        push rax
        push rdx
        push rsi
        push rdi
        push r8

; mov     rdx, 255
;        this is way too much
; we have a zero-terminated string,
; find its length
         xor rdx, rdx
.getlen:
         cmp byte [r8 + rdx], 0
         jz .gotlen
         add rdx, 1
         jmp .getlen
.gotlen:
; mov rsi, qword [r8]
; no, we want the address, not [contents]
        mov rsi, r8
mov     rdi,1
mov     rax, 1
syscall

; restore caller's registers
        pop r8
        pop rdi
        pop rsi
        pop rdx
        pop rax

        ret
;-----------------------

Am I even close, Gunner? I think that's what I'd try. Something "like" that, anyway...  This isn't going to "look good" since we print each digit as we get it. If the answer (after dividing by 16) were "1234", we would be printing "4342341234" (I think). That's probably not what you really want to do - not after getting it "debugged" anyway... I guess if it prints anything at all it's an "improvement". :)

Best,
Frank