diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm new file mode 100644 index 0000000..a644e7a --- /dev/null +++ b/03-asm-bios/task4.asm @@ -0,0 +1,121 @@ +global _start + +%define STDIN 0 +%define STDOUT 1 +%define STDERR 2 + +section .data + src db 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + src_size equ $-src + + ; резервируем 1 килобайт для буффера ввода и вывода + ; также в отдельной переменной сохраняем размер этого буфера + print_buf: times 1024 db 0 + buf_size equ $-print_buf + input_buf: times 1024 db 0 ; буфер, в который будет читаться символ со стандартного ввода + input_size equ $-src + + ; Для poll + %define POLLIN 0x001 ; Есть ли что почитать с буфера ввода. Понадобится для продолжения ввода + input_pollfd: + dd STDIN + dw POLLIN + 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 + RPOP_M rax, rsi, rdx, rdi + syscall + + RPOP_M rax, rsi, rdx, rdi ; вернем значения регистров + ret + +read_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 ; следим только за одним потоком +; +; RPOP_M rdi, rsi, rdx +; ret + + +_start: + mov rcx, src_size + mov rsi, src + mov rdi, print_buf + + xor rax, rax ; обнуляем регистр + .transfer: ; в цикле передаем данные, попутно конвертируя их в ascii + lodsb + DIGIT_TO_ASCII rax + stosb + loop .transfer + + mov [rdi + 1], BYTE `\n` ; Чтобы система не ругалась на отсутствие переноса + + mov rdi, src_size + call print_from_buf + +exit: + mov rax, 60 + mov rdi, 0 + syscall +