LINUX.ORG.RU

простой код на NASM

 , ,


0

2

В общем, хочу считать число из терминала и просто его вывести обратно. Проблема заключается в том, что при вводе строки из 4 или меньше символов ничего не выводится, а если не менее 5 символов то выводятся символы, начиная с 5. Я не могу найти и понять ошибку.

section .data
    num dd 0

section .bss
    buf resb 10
    
section .text
    global _start

_start:
    ; Считывание числа из терминала
    mov rax, 0 
    mov rdi, 0
    mov rsi, buf
    mov rdx, 10
    syscall
    
    ; Подготовка к перевода строки в число
    xor rax, rax
    xor rbx, rbx
    mov rbx, 10
    lea rsi, [buf]
    mov rcx, 10
    
convert_to_uint32_t:
    ; 10 раз считываем значение элементов массива buf
    ; из аски кода вычитаем код нуля => получаем цифру
    ; текущее число умножаем на 10 и прибавляем цифру
    cmp rcx, 0
    je end_convert
    xor rdx, rdx
    movzx rdx, byte[rsi]
    sub rdx, '0'
    mul rbx
    add rax, rdx
    inc rsi
    dec rcx
    jmp convert_to_uint32_t

end_convert:
    mov [num], rax
    
    lea rsi, [buf+10]     
    mov rax, [num]        
    xor rbx, rbx          
    mov rbx, 10          
    ; Обратное преобразованание числа в строку для вывода
convert_to_str:
    xor rdx, rdx      
    div rbx           
    add rdx, '0'      
    mov [rsi], rdx      
    dec rsi             
    cmp rax, 0          
    jne convert_to_str  

    ; Выводим строку числа
    mov rax, 1          
    mov rdi, 1          
    mov rsi, buf        
    mov rdx, 10 ;
    syscall

    ; Корректное завершение программы 
    mov rax, 60
    xor rdi, rdi
    syscall


Починил. Спрашивайте ваши вопросы.

section .data
    nl  db 10

section .bss
    buf resb 10
    
section .text
    global _start

_start:
    mov rax, 458920117
    call print_num
    call print_nl

    mov rax, 0
    mov rdi, 0
    mov rsi, buf
    mov rdx, 10
    syscall

    mov r8, rax
    xor rax, rax
    mov rbx, 10
    mov rsi, buf

convert_to_uint32_t:
    cmp r8, 0
    je  end_convert
    movzx rcx, byte[rsi]
    sub rcx, '0'
    jb  end_convert
    cmp rcx, 9
    ja  end_convert
    mul rbx
    add rax, rcx
    inc rsi
    dec r8
    jmp convert_to_uint32_t

end_convert:

    call print_num
    call print_nl

    mov rax, 60
    xor rdi, rdi
    syscall


print_num:
    lea rsi, [buf+10]
    mov rbx, 10
.convert_to_str:
    dec rsi
    xor rdx, rdx
    div rbx
    add rdx, '0'
    mov byte [rsi], dl
    cmp rax, 0
    jne .convert_to_str

    mov rax, 1
    mov rdi, 1
    lea rdx, [buf+10]
    sub rdx, rsi
    syscall

    ret

print_nl:
    mov rax, 1
    mov rdi, 1
    mov rdx, 1;
    lea rsi, [nl]
    syscall

    ret

wandrien ★★
()
Последнее исправление: wandrien (всего исправлений: 4)

Я не могу найти и понять ошибку

Неправильно преобразовывается строка в число(использование регистров в операции умножения), число в строку(перемещение остатка) и кривая работа с буфером при выводе строки(тут вообще все неправильно).

Вот код максимально близкий к оригиналу где это исправлено:

section .data
    num dd 0

section .bss
    buf resb 10
    
section .text
    global _start

_start:
    ; Считывание числа из терминала
    mov rax, 0 
    mov rdi, 0
    mov rsi, buf
    mov rdx, 10
    syscall
    
    ; Подготовка к перевода строки в число
    xor rax, rax
    xor rbx, rbx
    mov rbx, 10
    lea rsi, [buf]
    mov rcx, 10
    xor rdi, rdi
convert_to_uint32_t:
    ; 10 раз считываем значение элементов массива buf
    ; из аски кода вычитаем код нуля => получаем цифру
    ; текущее число умножаем на 10 и прибавляем цифру
    cmp rcx, 0
    je end_convert
    cmp byte[rsi], '0'
    jl end_convert
    cmp byte[rsi], '9'
    ja end_convert

    mov rax, rdi
    mul rbx
    mov rdi, rax
    movzx rax, byte[rsi]
    sub rax, '0'
    add rdi, rax
    inc rsi
    dec rcx
    jmp convert_to_uint32_t

end_convert:
    mov [num], rdi
    
    lea rsi, [buf+10]     
    mov rax, [num]        
    xor rbx, rbx          
    mov rbx, 10          
    ; Обратное преобразованание числа в строку для вывода
convert_to_str:
    xor rdx, rdx      
    div rbx           
    add rdx, '0'      
    mov byte[rsi], dl      
    dec rsi             
    cmp rax, 0          
    jne convert_to_str  

    ; Выводим строку числа
    mov rax, 1          
    mov rdi, 1
    lea rdx, [buf+10]
    sub rdx, rsi
    inc rdx     
    syscall

    ; Корректное завершение программы 
    mov rax, 60
    xor rdi, rdi
    syscall

PS

Если чё, я на ассемблере лет 25 не писал :)

arax ★★
()
Последнее исправление: arax (всего исправлений: 1)
Ответ на: комментарий от stabilitron

Да, алгоритмически можно было бы и обойтись. Просто не стоит много ожидать от кода, который был написан в 4 утра на скорую руку.

Там сначала я добавил только jb, отладил, потом почесал голову и добавил проверку на предмет символ > ‘9’. Первую проверку не убрал, хотя в unsigned арифметике она избыточна.

wandrien ★★
()