0

So I'm trying to implement itoa, which converts an int into a string. So far, the implementation is working if I don't loop in the .loop section, and stick to small numbers. As soon as it loops, my program segfaults.

Here is the code:

section .data
    buffer  times 11 db 0

section .text
    global  ft_itoa
    extern  ft_strrevd
    extern  malloc

ft_itoa:
    mov     rcx, 1                      ;initialize our counter at 1 for the terminating null byte
    mov     rax, rdi                    ;move number in RAX for DIV instruction
    push    rbx                         ;save RBX
    mov     bl, 10

.check_negative:
    and     edi, 0xf0000000
    mov     rdi, buffer
    jz      .loop                       ;number is positive, proceed to main loop
    not     rax                         ;else
    inc     rax                         ;compute absolute value with binary complement
    mov     r9, 1                       ;set neg flag

.loop:
    cmp     rax, 0
    jz      .check_neg_flag
    div     bl
    add     ah, 48                      ;convert int to char
    mov     byte[rdi + rcx - 1], ah     ;copy char in buffer
    sub     ah, 48
    inc     rcx
    jmp     .loop                       ;commenting this line prevents crash

.check_neg_flag:
    cmp     r9, 1
    jne     .dup
    mov     byte[rdi + rcx - 1], '-'
    inc     rcx

.dup:
    mov     byte[rdi + rcx - 1], 0
    call    ft_strrevd                  ;copy buffer string in memory and return pointer

.end:
    pop     rbx                         ;restore RBX
    ret

It's most likely caused by the div, but I'm having trouble understanding how it works. If anyone could point me towards a solution it'd be highly appreciated.

Jon Nimrod
  • 335
  • 1
  • 2
  • 12
  • `div bl` uses `ax` as dividend which is probably not what you want. Fault is generated if the result does not fit into 8 bits that is if `ax>=2560` in your case. That's for the first time around the loop, since after that `ah` is the remainder and you re-use that for dividend. – Jester Jan 26 '19 at 17:21
  • But if I use ebx to divide I get a floating point exception error. – Jon Nimrod Jan 26 '19 at 17:30
  • Well yeah the original code might not hit the FPE that I thought, maybe it just never terminates so `rcx` goes out of bounds. It's wrong nevertheless :) You will just have to make sure you divide what you want and use the proper size. – Jester Jan 26 '19 at 17:34
  • 1
    Okay, I managed to fix my problem using div ebx instead of bl. I tried that before but I had forget to clean edx before the div, which is what caused the FPE. Now it works, thank you! – Jon Nimrod Jan 26 '19 at 17:53

1 Answers1

0

So in order to fix this I have to use div ebx instead of div bl, and xor edx, edx before each div.

Here is a working version:

section .data
    buffer  times 11 db 0

    nega db "neg",0
    posi db "pos",0

section .text
    global  ft_itoa
    extern  ft_strdup
    extern  malloc

ft_itoa:
    xor     rcx, rcx                    ;initialize counter
    xor     r9, r9                      ;set neg flag to 0
    mov     eax, edi                    ;move number in RAX for DIV instruction
    push    rbx                         ;save RBX
    mov     ebx, 10

.check_negative:
    and     edi, 0x80000000
    mov     rdi, buffer
    jz      .divide                     ;number is positive, proceed to main loop
    not     eax                         ;else
    inc     eax                         ;compute absolute value with binary complement
    inc     r9                          ;set neg flag

.divide:
    xor     edx, edx
    div     ebx
    add     edx, 48                     ;convert int to char
    push    rdx
    inc     rcx
    cmp     eax, 0
    jnz     .divide

.check_neg_flag:
    cmp     r9, 1
    jne     .buff_string
    mov     byte[rdi], '-'

.buff_string:
    pop     rdx
    mov     byte[rdi + r9], dl
    dec     rcx
    inc     r9
    cmp     rcx, 0
    jnz     .buff_string

.dup:
    mov     byte[rdi + r9], 0
    call    ft_strdup                   ;copy buffer string in memory and return pointer
    pop     rbx                         ;restore RBX
    ret
Jon Nimrod
  • 335
  • 1
  • 2
  • 12