Files
solutions/03-asm-bios/task4.asm

149 lines
5.3 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

global _start
%define STDIN 0
%define STDOUT 1
%define STDERR 2
section .data
; резервируем 1 килобайт для буффера ввода и вывода
; также в отдельной переменной сохраняем размер этого буфера
print_buf: times 1024 db 0
buf_size equ $-print_buf
input_buf: times 1024 db 0 ; буфер, в который будут читаться символы со стандартного ввода
input_size equ $-input_buf
array: times 512 dq 0 ; молимся, чтобы никому не пришло в голову писать так много
arr_size equ $-array
; Для poll
%define POLLIN 0x001 ; Есть ли что почитать с буфера ввода. Понадобится для продолжения ввода
input_pollfd: dd STDIN
dw POLLIN
revents: dw 0 ; возвращаемые события
section .text
%macro DIGIT_TO_ASCII 1 ; макрос, принимающий один аргумент (регистр или память)
add %1, '0'
%endmacro
%macro ASCII_TO_DIGIT 1 ; макрос, принимающий один аргумент (регистр или память)
sub %1, '0'
%endmacro
%macro PUSH_M 1-* ; push many; пушит в порядке следования
%rep %0
push %1
%rotate 1
%endrep
%endmacro
%macro POP_M 1-* ; pop many. читает в порядке следования
%rep %0
pop %1
%rotate 1
%endrep
%endmacro
%macro RPOP_M 1-* ; pop many. читает в обратном порядке
%rotate -1
%rep %0
pop %1
%rotate -1
%endrep
%endmacro
; Передачу аргументов будем делать при помощи ABI - стандартная практика для linux
; Аргументы передаются в следующем порядке: rdi, rsi, rdx, rcx, r8, r9. Все, что не влезло, пушится в стек
; У передачи через стек тоже есть особенности, но их мы пока касаться не будем
clean_print_buf: ; none -> void
PUSH_M rax, rcx, rdi
mov rcx, buf_size
mov rdi, print_buf
xor rax, rax ; будем заносить нули во всю память
rep stosb
RPOP_M rax, rcx, rdi
ret
print_from_buf: ; word -> void
PUSH_M rax, rsi, rdx, rdi ; сохраним регистры, которые точно попортим
mov rdx, rdi ; сколько выводить, в rdi содержится единственный аргумент
mov rsi, print_buf ; откуда выводить. Адрес буфера
mov rdi, STDOUT; куда выводить. Дескриптор файла. В нашем случае стандартного вывода
mov rax, 1
syscall
RPOP_M rax, rsi, rdx, rdi ; вернем значения регистров
ret
read_to_buf: ; none -> void. Пытается заполнить буфер из стандартного ввода
PUSH_M rax, rdi, rsi
mov rdi, STDIN ; откуда читать (дескриптор файла)
mov rsi, input_buf ; куда читать
mov rdx, input_size ; Сколько пытаемся читать
mov rax, 0 ; системный вызов чтения
RPOP_M rax, rdi, rsi
ret
poll_stdin:
PUSH_M rdi, rsi, rdx
mov rsi, 1 ; следим только за одним потоком
mov rax, 7 ; poll syscall
mov rdi, input_pollfd
mov rsi, 1 ; одна структура данных (изначально просто вызов принимает кучу таких)
mov rdx, 0 ; не ждать
RPOP_M rdi, rsi, rdx
ret
_start:
mov rbp, rsp
; Создадим 2 локальные переменные для аккумулятора размером 8 байт и для математических нужд 8 байт.
; аккумулятор будет по адресу rbp - 8, а временная по rbp - 16
sub rsp, 16
mov rsi, input_buf
mov rdi, print_buf
.read_loop:
call read_to_buf ; системный вызов read вернет количество прочитаных байтов
mov rcx, rax ; сколько байтов прочиталось, столько и обработаем
; обработаем информацию
xor rax, rax ; обнулим на всякий пожарный
jmp .read_byte
.separator_occured:
push rcx
pop rcx
stosb
mov QWORD [rbp - 8], 0
.read_byte: ; цикл чтения
lodsb
; проверим, цифра ли это. Если нет, то записываем в память то, что хранилось в локальной переменной
cmp al, '0'
jl .separator_occured
cmp al, '9'
jg .separator_occured
ASCII_TO_DIGIT al ; Если цифра, то конвертируем ее из ascii
; Поскольку деление можно сделать только через регистр, придется извратиться
PUSH_M ax, rdx
mov rax, [rbp - 8]
mov qword [rbp - 16], 10
mul qword [rbp - 16]
mov [rbp - 8], rax
RPOP_M ax, rdx
add [rbp - 8], rax ; результат деления запишем в локальную переменную
loop .read_byte
call poll_stdin
test BYTE [revents], POLLIN
jnz .read_loop
exit:
mov rax, 60
mov rdi, 0
syscall