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