3 Commits

Author SHA1 Message Date
51e220410a feat: добавлено несколько полезных функций для решения 4 пункта 2024-09-22 17:55:49 +03:00
49d3c02d7d feat: task2 создан
Решен второй пункт в виде ассемблерного кода, однако он отформатирован вполне определенным образом
2024-09-22 15:27:21 +03:00
daec968bcb feat(utils): для чуть большего удоства написал Makefile
По факту он просто линкует одиночный файл ассемблерного кода и не подшивает никаких зависимостей. Весьма ситуативная фигня, но немного экономит время
2024-09-22 13:18:59 +03:00
3 changed files with 215 additions and 0 deletions

13
03-asm-bios/Makefile Normal file
View File

@ -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))

81
03-asm-bios/task2.asm Normal file
View File

@ -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

121
03-asm-bios/task4.asm Normal file
View File

@ -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