From daec968bcbf708b5b4173c3b293ecb4f6f5f61dc Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Sun, 22 Sep 2024 13:18:59 +0300 Subject: [PATCH 01/10] =?UTF-8?q?feat(utils):=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=87=D1=83=D1=82=D1=8C=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=83=D0=B4=D0=BE=D1=81=D1=82=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20Makefile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По факту он просто линкует одиночный файл ассемблерного кода и не подшивает никаких зависимостей. Весьма ситуативная фигня, но немного экономит время --- 03-asm-bios/Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 03-asm-bios/Makefile diff --git a/03-asm-bios/Makefile b/03-asm-bios/Makefile new file mode 100644 index 0000000..393f43d --- /dev/null +++ b/03-asm-bios/Makefile @@ -0,0 +1,13 @@ +ASM = nasm +ASM_FLAGS = -felf64 -g +LINK = ld + +%: %.o + $(LINK) -o $@ $^ + +%.o: %.asm + $(ASM) $(ASM_FLAGS) $^ -o $@ + +clean: + rm -f *.o + rm -f $(subst .asm, $(empty), $(wildcard *.asm)) From 49d3c02d7d5fe8a569cb61dfb9a28c96b46e2cc7 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Sun, 22 Sep 2024 15:27:21 +0300 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20task2=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Решен второй пункт в виде ассемблерного кода, однако он отформатирован вполне определенным образом --- 03-asm-bios/task2.asm | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 03-asm-bios/task2.asm diff --git a/03-asm-bios/task2.asm b/03-asm-bios/task2.asm new file mode 100644 index 0000000..579373a --- /dev/null +++ b/03-asm-bios/task2.asm @@ -0,0 +1,81 @@ +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 + +section .text + +%macro DIGIT_TO_ASCII 1 ; макрос, принимающий один регистр + add %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. Все, что не влезло, пушится в стек +; У передачи через стек тоже есть особенности, но их мы пока касаться не будем + +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 + +_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 + From 51e220410a29b0ef93841bed01655da348423f17 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Sun, 22 Sep 2024 17:55:49 +0300 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B7=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=204?= =?UTF-8?q?=20=D0=BF=D1=83=D0=BD=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/task4.asm | 121 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 03-asm-bios/task4.asm 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 + From 58897fedb71007b27f90191b089cedc4721463fc Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Sun, 22 Sep 2024 22:07:18 +0300 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D0=B4?= =?UTF-8?q?=D1=83=D1=80=D0=B0=20pollin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/task4.asm | 50 +++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm index a644e7a..c703cb1 100644 --- a/03-asm-bios/task4.asm +++ b/03-asm-bios/task4.asm @@ -12,15 +12,14 @@ section .data ; также в отдельной переменной сохраняем размер этого буфера print_buf: times 1024 db 0 buf_size equ $-print_buf - input_buf: times 1024 db 0 ; буфер, в который будет читаться символ со стандартного ввода + input_buf: times 1024 db 0 ; буфер, в который будут читаться символы со стандартного ввода input_size equ $-src ; Для poll %define POLLIN 0x001 ; Есть ли что почитать с буфера ввода. Понадобится для продолжения ввода - input_pollfd: - dd STDIN - dw POLLIN - dw 0 + input_pollfd: dd STDIN + dw POLLIN + revents: dw 0 ; возвращаемые события section .text @@ -68,19 +67,16 @@ clean_print_buf: ; none -> void 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. Пытается заполнить буфер из стандартного ввода +read_to_buf: ; none -> void. Пытается заполнить буфер из стандартного ввода PUSH_M rax, rdi, rsi mov rdi, STDIN ; откуда читать (дескриптор файла) mov rsi, input_buf ; куда читать @@ -89,30 +85,24 @@ read_buf: ; none -> void. Пытается заполнить буфер из с RPOP_M rax, rdi, rsi ret -;poll_stdin: -; PUSH_M rdi, rsi, rdx -; mov rsi, 1 ; следим только за одним потоком -; -; RPOP_M rdi, rsi, rdx -; 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 rcx, src_size - mov rsi, src - mov rdi, print_buf - - xor rax, rax ; обнуляем регистр - .transfer: ; в цикле передаем данные, попутно конвертируя их в ascii - lodsb - DIGIT_TO_ASCII rax - stosb - loop .transfer + .read_loop: + call read_to_buf + ; process - mov [rdi + 1], BYTE `\n` ; Чтобы система не ругалась на отсутствие переноса - - mov rdi, src_size - call print_from_buf + call poll_stdin + test BYTE [revents], POLLIN + jnz .read_loop exit: mov rax, 60 From 6c1198df7396be4a9f6edc3d9b3e1e4b110737f2 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Sun, 22 Sep 2024 23:57:16 +0300 Subject: [PATCH 05/10] =?UTF-8?q?sync:=20=D0=BF=D1=80=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BB=20=D1=87=D0=B0=D1=81=D1=82=D1=8C=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=204=20?= =?UTF-8?q?=D0=BF=D1=83=D0=BD=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/task4.asm | 49 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm index c703cb1..2b03793 100644 --- a/03-asm-bios/task4.asm +++ b/03-asm-bios/task4.asm @@ -5,15 +5,17 @@ global _start %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 + input_size equ $-input_buf + + array: times 512 dq 0 ; молимся, чтобы никому не пришло в голову писать так много + arr_size equ $-array ; Для poll %define POLLIN 0x001 ; Есть ли что почитать с буфера ввода. Понадобится для продолжения ввода @@ -90,15 +92,50 @@ poll_stdin: mov rsi, 1 ; следим только за одним потоком mov rax, 7 ; poll syscall mov rdi, input_pollfd - mov rsi, 1 ; одна структура данных + 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 - ; process + 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 From ed21dfe07a86b1953d634724e5f23df012fe2449 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Mon, 23 Sep 2024 18:49:23 +0300 Subject: [PATCH 06/10] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D1=81=20=D1=86=D0=B8=D0=BA=D0=BB=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/task4.asm | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm index 2b03793..0270f84 100644 --- a/03-asm-bios/task4.asm +++ b/03-asm-bios/task4.asm @@ -79,12 +79,13 @@ print_from_buf: ; word -> void ret read_to_buf: ; none -> void. Пытается заполнить буфер из стандартного ввода - PUSH_M rax, rdi, rsi + PUSH_M rdi, rsi, rdx mov rdi, STDIN ; откуда читать (дескриптор файла) mov rsi, input_buf ; куда читать mov rdx, input_size ; Сколько пытаемся читать mov rax, 0 ; системный вызов чтения - RPOP_M rax, rdi, rsi + syscall + RPOP_M rdi, rsi, rdx ; rax содержит количество прочитанных байт, а это важно ret poll_stdin: @@ -94,6 +95,7 @@ poll_stdin: mov rdi, input_pollfd mov rsi, 1 ; одна структура данных (изначально просто вызов принимает кучу таких) mov rdx, 0 ; не ждать + syscall RPOP_M rdi, rsi, rdx ret @@ -104,19 +106,21 @@ _start: sub rsp, 16 mov rsi, input_buf - mov rdi, print_buf + mov rdi, array .read_loop: call read_to_buf ; системный вызов read вернет количество прочитаных байтов mov rcx, rax ; сколько байтов прочиталось, столько и обработаем ; обработаем информацию xor rax, rax ; обнулим на всякий пожарный jmp .read_byte + .separator_occured: - push rcx - - pop rcx - stosb + dec rcx + mov rax, [rbp - 8] + stosq mov QWORD [rbp - 8], 0 + test rcx, rcx + jz .check_buf .read_byte: ; цикл чтения lodsb @@ -127,7 +131,7 @@ _start: jg .separator_occured ASCII_TO_DIGIT al ; Если цифра, то конвертируем ее из ascii - ; Поскольку деление можно сделать только через регистр, придется извратиться + ; Поскольку умножение и деление можно сделать только через регистр, придется извратиться PUSH_M ax, rdx mov rax, [rbp - 8] mov qword [rbp - 16], 10 @@ -135,8 +139,9 @@ _start: mov [rbp - 8], rax RPOP_M ax, rdx add [rbp - 8], rax ; результат деления запишем в локальную переменную - loop .read_byte + loop .read_byte ; читаем буфер ввода до конца + .check_buf: call poll_stdin test BYTE [revents], POLLIN jnz .read_loop From e1aeb3f2df1c18d7b4745c4e9ebd870fd9e980f0 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Mon, 23 Sep 2024 20:45:46 +0300 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=B5=D1=80=D0=B2=D1=8B=D0=B9=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D1=82=D0=B8=D0=BF=20=D1=80=D0=B5=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Прототип еще не тестировался --- 03-asm-bios/task4.asm | 59 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm index 0270f84..ed69cae 100644 --- a/03-asm-bios/task4.asm +++ b/03-asm-bios/task4.asm @@ -55,6 +55,11 @@ section .text %endrep %endmacro +%macro PUSHR8 1; закинуть восьмибитный регистр в стек + dec rsp + mov [rsp], %1 +%endmacro + ; Передачу аргументов будем делать при помощи ABI - стандартная практика для linux ; Аргументы передаются в следующем порядке: rdi, rsi, rdx, rcx, r8, r9. Все, что не влезло, пушится в стек ; У передачи через стек тоже есть особенности, но их мы пока касаться не будем @@ -68,7 +73,7 @@ clean_print_buf: ; none -> void RPOP_M rax, rcx, rdi ret -print_from_buf: ; word -> void +print_from_buf: ; qword -> void; пытается вывести данные из буфера. аргумент не может быть больше 1024 PUSH_M rax, rsi, rdx, rdi ; сохраним регистры, которые точно попортим mov rdx, rdi ; сколько выводить, в rdi содержится единственный аргумент mov rsi, print_buf ; откуда выводить. Адрес буфера @@ -99,11 +104,44 @@ poll_stdin: RPOP_M rdi, rsi, rdx ret +print_number: ; qword (rdi) -> void + ; наша задача - сформировать массив символов. + ; Ну а раз мы не знаем точно сколько их будет, формировать его будем прямо в стеке. нам повезло, что он растет вниз + ; Нам очень повезло, что он растет вниз + ; создадим 2 локальные переменные - одну для размера массива, другую для делителя + push rbp + PUSH_M rdx, rdi, rsi ; сохранять регистры обязательно надо до того, как писать в стек символы + ; создаем базу для адресации. Тогда первая будет на rbp - 8 - делитель, а вторая на rbp - 16 - количество + mov rbp, rsp + ; [WARNING] тут надо будет сохранить регистры + sub rsp, 16 ; выделяем место под 2 переменные + mov qword [rbp - 8], 10 ; пусть и жирно, но операнд обязан быть 64 разрядным для корректного деления + mov qword [rbp - 16], 0 ; счетчик + mov rax, rdi + .division_loop: + xor rdx, rdx ; обнулим найденый остаток. (он просто еще и при делении принимает участие) + div qword [rbp - 8] + DIGIT_TO_ASCII dl + PUSHR8 dl ; поскольку в процессор не завезли возможность закинуть в стек 8 битный регистр, я им немного помог макросами + inc qword [rbp - 16] ; увеличиваем счетчик на единицу + test rax, rax ; делает and поразрядное с самим собой. Меня интересует, лежит ли в rax ноль + jnz .division_loop ; если в rax не ноль, то продолжаем цикл + ; выводим число + mov rax, 1 + mov rdi, STDOUT + mov rsi, rsp + mov rdx, [rbp-16] + add rsp, 16 ; освобождаем память + RPOP_M rdx, rdi, rsi + pop rbp + _start: mov rbp, rsp ; Создадим 2 локальные переменные для аккумулятора размером 8 байт и для математических нужд 8 байт. ; аккумулятор будет по адресу rbp - 8, а временная по rbp - 16 sub rsp, 16 + ; потом я не удержался и завел еще одну переменную - сколько мы успели написать в массив + sub rsp, 2 ; массив все равно размером всего 512, делать переменную больше нет смысла. rbp - 18 mov rsi, input_buf mov rdi, array @@ -118,7 +156,8 @@ _start: dec rcx mov rax, [rbp - 8] stosq - mov QWORD [rbp - 8], 0 + inc word [rbp - 18] + mov qword [rbp - 8], 0 test rcx, rcx jz .check_buf @@ -146,6 +185,22 @@ _start: test BYTE [revents], POLLIN jnz .read_loop + ; Теперь выведем прочитанный массив на экран + xor rcx, rcx + mov cx, [rbp - 18] + .output_loop: + mov rsi, array + lodsq + mov rdi, rax + call print_number + mov byte [print_buf], ' ' + mov rdi, 1 + call print_from_buf ; печатаем ровно 1 пробел + loop .output_loop + mov byte [print_buf], `\n` + mov rdi, 1 + call print_from_buf + exit: mov rax, 60 mov rdi, 0 From 78a4638401c74e5e9c92caad296a434a0438b0d1 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Tue, 24 Sep 2024 12:06:11 +0300 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/task4.asm | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/03-asm-bios/task4.asm b/03-asm-bios/task4.asm index ed69cae..37d281d 100644 --- a/03-asm-bios/task4.asm +++ b/03-asm-bios/task4.asm @@ -79,7 +79,9 @@ print_from_buf: ; qword -> void; пытается вывести данные и mov rsi, print_buf ; откуда выводить. Адрес буфера mov rdi, STDOUT; куда выводить. Дескриптор файла. В нашем случае стандартного вывода mov rax, 1 + push rcx syscall + pop rcx RPOP_M rax, rsi, rdx, rdi ; вернем значения регистров ret @@ -114,26 +116,33 @@ print_number: ; qword (rdi) -> void ; создаем базу для адресации. Тогда первая будет на rbp - 8 - делитель, а вторая на rbp - 16 - количество mov rbp, rsp ; [WARNING] тут надо будет сохранить регистры - sub rsp, 16 ; выделяем место под 2 переменные - mov qword [rbp - 8], 10 ; пусть и жирно, но операнд обязан быть 64 разрядным для корректного деления - mov qword [rbp - 16], 0 ; счетчик + push rsp ; сохраню, потому что после всей вакханалии я концов не сыщу + sub rsp, 16 ; выделяем место под 3 переменные + mov qword [rbp - 16], 10 ; пусть и жирно, но операнд обязан быть 64 разрядным для корректного деления + mov qword [rbp - 24], 0 ; счетчик mov rax, rdi + push byte 0 ; при выводе он ориентируется на это как на конец строки .division_loop: xor rdx, rdx ; обнулим найденый остаток. (он просто еще и при делении принимает участие) - div qword [rbp - 8] + div qword [rbp - 16] DIGIT_TO_ASCII dl PUSHR8 dl ; поскольку в процессор не завезли возможность закинуть в стек 8 битный регистр, я им немного помог макросами - inc qword [rbp - 16] ; увеличиваем счетчик на единицу + inc qword [rbp - 24] ; увеличиваем счетчик на единицу test rax, rax ; делает and поразрядное с самим собой. Меня интересует, лежит ли в rax ноль jnz .division_loop ; если в rax не ноль, то продолжаем цикл ; выводим число mov rax, 1 mov rdi, STDOUT mov rsi, rsp - mov rdx, [rbp-16] - add rsp, 16 ; освобождаем память + mov rdx, [rbp-24] ; уже не надо очищать, потому что в конце я просто восстановлю как было + push rcx + syscall + pop rcx + + mov rsp, [rbp - 8] RPOP_M rdx, rdi, rsi pop rbp + ret _start: mov rbp, rsp @@ -156,6 +165,7 @@ _start: dec rcx mov rax, [rbp - 8] stosq + xor rax, rax inc word [rbp - 18] mov qword [rbp - 8], 0 test rcx, rcx @@ -171,25 +181,26 @@ _start: ASCII_TO_DIGIT al ; Если цифра, то конвертируем ее из ascii ; Поскольку умножение и деление можно сделать только через регистр, придется извратиться - PUSH_M ax, rdx + PUSH_M rax, rdx mov rax, [rbp - 8] mov qword [rbp - 16], 10 mul qword [rbp - 16] mov [rbp - 8], rax - RPOP_M ax, rdx + RPOP_M rax, rdx add [rbp - 8], rax ; результат деления запишем в локальную переменную loop .read_byte ; читаем буфер ввода до конца .check_buf: call poll_stdin - test BYTE [revents], POLLIN + test dword [revents], POLLIN jnz .read_loop ; Теперь выведем прочитанный массив на экран xor rcx, rcx mov cx, [rbp - 18] - .output_loop: mov rsi, array + call clean_print_buf + .output_loop: lodsq mov rdi, rax call print_number From 23b82657d4fa441195e9c1a70a1ad4c5b972966a Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Tue, 24 Sep 2024 12:11:54 +0300 Subject: [PATCH 09/10] =?UTF-8?q?docs:=20=D0=B2=D0=BD=D0=B5=D1=81=20=D0=BC?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D0=BD=D1=8C=D0=BA=D0=BE=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=8F=D1=81=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/03-asm-bios/README.md b/03-asm-bios/README.md index 76e4193..0487dbe 100644 --- a/03-asm-bios/README.md +++ b/03-asm-bios/README.md @@ -2,3 +2,7 @@ ## Ассемблер и функции BIOS +В этой работе намного проще посмотреть непосредственно решения и почитать комментарии к коду, чем читать теоретическое приложение к работе. Если вам все же что-то не понятно - кидайте в issues + +Впрочем зная, что основная масса народу не будет делать эту лабу так, как сделал ее я, сюда вряд ли кто-то заглянет) + From 8fc6112f5850d5d50b185b3f8a80d7082d55a187 Mon Sep 17 00:00:00 2001 From: Miheev Egor Date: Tue, 24 Sep 2024 12:17:40 +0300 Subject: [PATCH 10/10] =?UTF-8?q?docs:=20=D0=BF=D0=BE=D1=8F=D1=81=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D1=83=20Makefile=20=D0=B2=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-asm-bios/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/03-asm-bios/README.md b/03-asm-bios/README.md index 0487dbe..ac8cd73 100644 --- a/03-asm-bios/README.md +++ b/03-asm-bios/README.md @@ -6,3 +6,9 @@ Впрочем зная, что основная масса народу не будет делать эту лабу так, как сделал ее я, сюда вряд ли кто-то заглянет) +### Касаемо Makefile + +Для того чтобы не писать много команд для однотипной и монотонной сборки проекта, был написан простой Makefile. Однако работает он следующим образом: он принимает название цели сборки и ищет файл с именем цели и расширением .asm. Если не находит - не собирает цель. + +Важно заметить, что он не умеет линковать другие файлы в ассемблер, потому что написан был не для этого. Он просто берет голый файл на NASM (обязательно) и выдает 64-битный ELF из этого единственного файла. Если вам необходимо что-то прилинковать к ассемблеру, то увы, придется собирать проект вручную или менять этот makefile +