mirror of
https://github.com/javalsai/aoc.git
synced 2026-01-12 17:10:00 +01:00
d01p2, asm 💪
This commit is contained in:
3
2024/01/p2/.gitignore
vendored
Normal file
3
2024/01/p2/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/*.o
|
||||
/input.txt
|
||||
/main
|
||||
5
2024/01/p2/build.sh
Executable file
5
2024/01/p2/build.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
nasm -f elf64 -o main.o main.asm
|
||||
ld -o main main.o
|
||||
563
2024/01/p2/main.asm
Normal file
563
2024/01/p2/main.asm
Normal file
@@ -0,0 +1,563 @@
|
||||
%define OS_READ 0
|
||||
%define OS_WRITE 1
|
||||
%define OS_OPEN 2
|
||||
%define OS_CLOSE 3
|
||||
%define OS_MMAP 9
|
||||
%define OS_MUNMAP 11
|
||||
%define OS_EXIT 60
|
||||
|
||||
%define O_RDONLY 0b000
|
||||
%define O_WRONLY 0b001
|
||||
%define O_RDWR 0b010
|
||||
; there's more opts for dir, create, excl, noctty, nofollow...
|
||||
|
||||
%define PROT_NONE 0b000
|
||||
%define PROT_READ 0b001
|
||||
%define PROT_WRITE 0b010
|
||||
%define PROT_EXEC 0b100
|
||||
|
||||
%define MAP_PRIVATE 0b10
|
||||
; also more opts ig
|
||||
|
||||
%define FD_STDIN 0
|
||||
%define FD_STDOUT 1
|
||||
%define FD_STDERR 2
|
||||
|
||||
; ---
|
||||
|
||||
section .bss
|
||||
ptos_str: resb 16
|
||||
|
||||
section .rodata
|
||||
PTR_0X: db "0x"
|
||||
NEWLINE: db 10
|
||||
ZERO_DEV: db "/dev/zero", 0
|
||||
|
||||
MSG_FOPENING_1: db 0x1b, "[36m", "Opening '"
|
||||
MSG_FOPENING_1_LEN: equ $ - MSG_FOPENING_1
|
||||
MSG_FOPENING_2: db "'...", 0x1b, "[0m", 10
|
||||
MSG_FOPENING_2_LEN: equ $ - MSG_FOPENING_2
|
||||
|
||||
ERRMSG_NOARG: db 0x1b, "[1;31m"
|
||||
db "Proper arguments not provided:", 10
|
||||
db " Usage: ./main <input path> <alignemnt>"
|
||||
db 0x1b, "[0m", 10
|
||||
ERRMSG_NOARG_LEN: equ $ - ERRMSG_NOARG
|
||||
ERRMSG_FOPEN: db 0x1b, "[1;31m", "Error opening", 0x1b, "[0m", 10
|
||||
ERRMSG_FOPEN_LEN: equ $ - ERRMSG_FOPEN
|
||||
ERRMSG_MALLOC: db 0x1b, "[1;31m", "Error allocating memory", 0x1b, "[0m", 10
|
||||
ERRMSG_MALLOC_LEN: equ $ - ERRMSG_MALLOC
|
||||
ERRMSG_UNFULLREAD: db 0x1b, "[1;31m", "Read an unaligned ammount of bytes", 0x1b, "[0m", 10
|
||||
ERRMSG_UNFULLREAD_LEN: equ $ - ERRMSG_UNFULLREAD
|
||||
|
||||
DBGMSG_READLN: db " - read an 'aligned' line", 10
|
||||
DBGMSG_READLN_LEN: equ $ - DBGMSG_READLN
|
||||
DBGMSG_READLNFNSH: db "finished reading lines", 10
|
||||
DBGMSG_READLNFNSH_LEN: equ $ - DBGMSG_READLNFNSH
|
||||
|
||||
section .data
|
||||
demo_arr: dq 1, 4, 2, 3, 4, 2
|
||||
demo_arr_len: equ $ - demo_arr
|
||||
|
||||
section .text
|
||||
global _start
|
||||
|
||||
_start:
|
||||
mov rbp, rsp
|
||||
sub rsp, 40
|
||||
; [rbp-8]: input fd
|
||||
; [rbp-16]: alignment
|
||||
; [rbp-24]: read buf
|
||||
; [rbp-32]: position of stack before the array alloc thing
|
||||
; basically pseudo stack frame
|
||||
|
||||
mov rax, [rbp] ; argc
|
||||
cmp rax, 3
|
||||
je .correct_args
|
||||
mov rsi, ERRMSG_NOARG
|
||||
mov rdx, ERRMSG_NOARG_LEN
|
||||
jmp errmsg
|
||||
.correct_args:
|
||||
|
||||
mov rdi, [rbp+16] ; argv[1]
|
||||
call open_file
|
||||
mov [rbp-8], rax
|
||||
|
||||
mov rsi, [rbp+24] ; argv[2]
|
||||
mov rdi, 10
|
||||
call stoi ; num in rax
|
||||
mov [rbp-16], rax
|
||||
|
||||
call malloc ; takes rax too
|
||||
; and we get ptr in rax
|
||||
mov [rbp-24], rax
|
||||
|
||||
mov [rbp-32], rsp
|
||||
.read_loop:
|
||||
mov rax, OS_READ
|
||||
mov rdi, [rbp-8]
|
||||
mov rsi, [rbp-24]
|
||||
mov rdx, [rbp-16]
|
||||
syscall
|
||||
test rax, rax
|
||||
jz .read_loop_end
|
||||
cmp rax, [rbp-16]
|
||||
je .read_full_aligned
|
||||
mov rsi, ERRMSG_UNFULLREAD
|
||||
mov rdx, ERRMSG_UNFULLREAD_LEN
|
||||
jmp errmsg
|
||||
.read_full_aligned:
|
||||
|
||||
; so we pass an arg from stack
|
||||
; + reserving an additional entry
|
||||
sub rsp, 8
|
||||
push qword [rbp-24] ; ptr
|
||||
call line_parser
|
||||
; and we dont restore stack position
|
||||
; we store here until we know length
|
||||
; to malloc and get it out
|
||||
|
||||
jmp .read_loop
|
||||
.read_loop_end:
|
||||
|
||||
; and at this point we can redefine
|
||||
; [rbp-8]: input fd
|
||||
; [rbp-16]: alignment
|
||||
; [rbp-24]: read buf
|
||||
; but close all that before
|
||||
mov rax, OS_CLOSE
|
||||
mov rdi, [rbp-8]
|
||||
syscall
|
||||
mov rdi, [rbp-24]
|
||||
mov rsi, [rbp-16]
|
||||
call free
|
||||
; and now
|
||||
; [rbp-8]: list1 ptr
|
||||
; [rbp-16]: list2 ptr
|
||||
; [rbp-24]: each list size
|
||||
|
||||
; nooow, we have all that shii in stack
|
||||
; so we qalc the size (sub looks reversed bsc stack goes down)
|
||||
mov rax, [rbp-32]
|
||||
sub rax, rsp
|
||||
shr rax, 1 ; and divide by 2 ("double list")
|
||||
mov [rbp-24], rax
|
||||
|
||||
call malloc
|
||||
mov [rbp-8], rax
|
||||
|
||||
mov rax, [rbp-24]
|
||||
call malloc
|
||||
mov [rbp-16], rax
|
||||
|
||||
|
||||
; and "deinterlace" lists from stack to the mem vecs
|
||||
mov rax, [rbp-24]
|
||||
mov rbx, [rbp-8]
|
||||
mov rcx, [rbp-16]
|
||||
.deint_loop:
|
||||
sub rax, 8
|
||||
|
||||
pop r10
|
||||
pop r11
|
||||
mov [rbx+rax], r10
|
||||
mov [rcx+rax], r11
|
||||
|
||||
test rax, rax
|
||||
jnz .deint_loop
|
||||
|
||||
; and now we can also redefine
|
||||
; [rbp-32]: accumulator (rsp should be back to original place after popping that)
|
||||
mov qword [rbp-32], 0
|
||||
|
||||
; mov rax, demo_arr
|
||||
; mov rsi, demo_arr_len
|
||||
; mov rdi, 2
|
||||
; call count_n
|
||||
; mov rax, rsi
|
||||
; call ptos
|
||||
; call print_ptos
|
||||
|
||||
; iter index (reverse-iter) (size)
|
||||
mov r11, [rbp-24]
|
||||
.cmp_loop:
|
||||
sub r11, 8
|
||||
; get next smolest in list1
|
||||
mov rax, [rbp-8]
|
||||
mov rsi, [rbp-24]
|
||||
mov rdi, [rax+r11]
|
||||
call count_n
|
||||
mov r12, rdi ; save num in r12
|
||||
|
||||
mov rax, [rbp-16]
|
||||
mov rsi, [rbp-24]
|
||||
; rdi preserved
|
||||
call count_n
|
||||
; count in rsi
|
||||
|
||||
mov rax, r12 ; first num
|
||||
mul rsi ; rdx:rax = rax * r/m64 (we just ignore rdx :P)
|
||||
add [rbp-32], rax
|
||||
|
||||
test r11, r11
|
||||
jnz .cmp_loop
|
||||
|
||||
mov rax, [rbp-32]
|
||||
mov rdi, 10
|
||||
call itos
|
||||
mov rax, r10
|
||||
mov rdi, r9
|
||||
call just_print
|
||||
call print_newline
|
||||
|
||||
; exit
|
||||
mov rdi, 0
|
||||
_exit:
|
||||
mov rax, OS_EXIT
|
||||
syscall
|
||||
|
||||
; count n in list
|
||||
; rax: list ptr
|
||||
; rsi: list size (bytes)
|
||||
; rdi: num to count
|
||||
; returns:
|
||||
; rsi: amount
|
||||
; [everything preserved but rsi and rdx]
|
||||
count_n:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8
|
||||
; [rbp-8]: count
|
||||
|
||||
mov qword [rbp-8], 0
|
||||
.count:
|
||||
sub rsi, 8
|
||||
mov rdx, [rax+rsi]
|
||||
cmp rdi, rdx
|
||||
jnz .after_add
|
||||
inc qword [rbp-8]
|
||||
.after_add:
|
||||
|
||||
test rsi, rsi
|
||||
jnz .count
|
||||
|
||||
mov rsi, [rbp-8]
|
||||
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
; takes [rsp+8/rbp+16]: ptr
|
||||
; returns:
|
||||
; [rsp+8 /rbp+16]: 1st num
|
||||
; [rsp+16/rbp+24]: 2nd num
|
||||
line_parser:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8 ; no need for alignment
|
||||
; [rbp-8]: start of 2nd num
|
||||
|
||||
; nullify first space to stoi it
|
||||
mov rax, [rbp+16]
|
||||
.null_loop:
|
||||
inc rax
|
||||
cmp byte [rax], " "
|
||||
jne .null_loop
|
||||
mov byte [rax], 0
|
||||
; now same but find the start
|
||||
.start_2nd_loop:
|
||||
inc rax
|
||||
cmp byte [rax], " "
|
||||
je .start_2nd_loop
|
||||
mov [rbp-8], rax
|
||||
; and stoi also needs nullbyte, not newline
|
||||
.newline_loop:
|
||||
inc rax
|
||||
cmp byte [rax], 10 ; 10 = '\n'
|
||||
jne .newline_loop
|
||||
mov byte [rax], 0
|
||||
|
||||
mov rdi, 10
|
||||
mov rsi, [rbp+16]
|
||||
call stoi
|
||||
mov [rbp+16], rax
|
||||
mov rsi, [rbp-8]
|
||||
call stoi
|
||||
mov [rbp+24], rax
|
||||
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
; takes:
|
||||
; rdi: char* path
|
||||
; returns rax: fd
|
||||
open_file:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8 ; reserve 8B
|
||||
|
||||
mov qword [rbp-8], rdi
|
||||
|
||||
mov rsi, MSG_FOPENING_1
|
||||
mov rdx, MSG_FOPENING_1_LEN
|
||||
call print
|
||||
mov rax, qword [rbp-8]
|
||||
call just_print_null
|
||||
mov rsi, MSG_FOPENING_2
|
||||
mov rdx, MSG_FOPENING_2_LEN
|
||||
call print
|
||||
|
||||
mov rax, OS_OPEN
|
||||
mov rsi, O_RDONLY
|
||||
mov rdi, [rbp-8]
|
||||
mov rdx, 0
|
||||
syscall
|
||||
; fd in rax
|
||||
|
||||
cmp rax, 0
|
||||
jg .valid_fd ; rax > 0 (signed)
|
||||
mov rsi, ERRMSG_FOPEN
|
||||
mov rdx, ERRMSG_FOPEN_LEN
|
||||
jmp errmsg
|
||||
.valid_fd:
|
||||
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
; takes:
|
||||
; rsi: errmsg ptr
|
||||
; rdx: errmsg len
|
||||
errmsg:
|
||||
mov rdi, FD_STDERR
|
||||
call print_fd
|
||||
mov rdi, 1
|
||||
jmp _exit
|
||||
print:
|
||||
mov rdi, FD_STDOUT
|
||||
; same & rdi: fd
|
||||
print_fd:
|
||||
mov rax, OS_WRITE
|
||||
syscall
|
||||
ret
|
||||
|
||||
; ---- printing
|
||||
just_print_null:
|
||||
mov rdi, rax,
|
||||
.count_til_null:
|
||||
inc rdi
|
||||
movzx rdx, byte [rdi]
|
||||
test rdx, rdx
|
||||
jnz .count_til_null
|
||||
sub rdi, rax
|
||||
just_print:
|
||||
mov rsi, rax
|
||||
mov rdx, rdi
|
||||
mov rax, OS_WRITE
|
||||
mov rdi, FD_STDOUT
|
||||
syscall
|
||||
ret
|
||||
|
||||
; ---- ptos
|
||||
; pointer to string
|
||||
; takes:
|
||||
; rax: pointer
|
||||
; returns:
|
||||
; rsi: memory block (freeable when needed)
|
||||
; r10: start ptr (within block)
|
||||
; r9: str len
|
||||
; garbage:
|
||||
; rax: consumed integer
|
||||
; rsi: 16 base :)
|
||||
; notes:
|
||||
; div => rdx:rax / r/m64 => rax(quot), rdx(remnd)
|
||||
ptos:
|
||||
call nullify_ptros_ptr
|
||||
; save registers
|
||||
mov rsi, ptos_str
|
||||
mov rdi, 16
|
||||
; align rsi ptr (we write from end)
|
||||
mov r10, rsi
|
||||
add r10, 16 ; we do an extra number cuz alignment and less intructs
|
||||
.ptos_iter:
|
||||
dec r10
|
||||
mov rdx, 0
|
||||
div rdi
|
||||
cmp rdx, 10
|
||||
jl .ptos_iter_after_alpha_shift
|
||||
add rdx, 7
|
||||
.ptos_iter_after_alpha_shift:
|
||||
add rdx, 48
|
||||
mov byte [r10], dl
|
||||
test rax,rax
|
||||
jnz .ptos_iter
|
||||
.ptos_return:
|
||||
mov r9, rsi
|
||||
add r9, 64
|
||||
sub r9, r10
|
||||
ret
|
||||
nullify_ptros_ptr:
|
||||
push rax
|
||||
mov rax, 16
|
||||
.npp_iter:
|
||||
dec rax
|
||||
mov [ptos_str+rax], byte '0'
|
||||
test rax, rax
|
||||
jnz .npp_iter
|
||||
pop rax
|
||||
ret
|
||||
print_ptos:
|
||||
mov rax, OS_WRITE
|
||||
mov rdi, FD_STDOUT
|
||||
mov rsi, PTR_0X
|
||||
mov rdx, 2
|
||||
syscall
|
||||
mov rax, OS_WRITE
|
||||
mov rsi, ptos_str
|
||||
mov rdx, 16
|
||||
syscall
|
||||
print_newline:
|
||||
mov rax, OS_WRITE
|
||||
mov rdi, FD_STDOUT
|
||||
mov rsi, NEWLINE
|
||||
mov rdx, 1
|
||||
syscall
|
||||
ret
|
||||
|
||||
|
||||
; -- malloc
|
||||
; takes:
|
||||
; rax: size
|
||||
; returns:
|
||||
; rax: addr
|
||||
;
|
||||
; /dev/null's fd gets lost tho
|
||||
;
|
||||
malloc:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8 ; reserve 8B, no alignment needed
|
||||
|
||||
mov qword [rbp-8], rax
|
||||
|
||||
; open /dev/null
|
||||
mov rax, OS_OPEN
|
||||
mov rdi, ZERO_DEV
|
||||
mov rsi, O_RDWR
|
||||
mov rdx, 0
|
||||
syscall
|
||||
; fd in rax
|
||||
|
||||
; mmap it
|
||||
mov r8, rax ; fd into r8
|
||||
mov r9, 0 ; "off"?
|
||||
mov rax, OS_MMAP
|
||||
mov rdi, 0
|
||||
mov rsi, [rbp-8]
|
||||
mov rdx, PROT_READ | PROT_WRITE
|
||||
mov r10, MAP_PRIVATE
|
||||
syscall
|
||||
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
; -- free
|
||||
; takes:
|
||||
; rdi: ptr
|
||||
; rsi: size
|
||||
free:
|
||||
mov rax, OS_MUNMAP
|
||||
syscall
|
||||
ret
|
||||
|
||||
; -- stoi / itos
|
||||
; TODO: moar than 10 radix
|
||||
|
||||
; string to interger (ik ppl call this atoi, but nvm)
|
||||
; takes:
|
||||
; string pointer (null terminated): rsi
|
||||
; radix: rdi
|
||||
; returns:
|
||||
; rax: result
|
||||
; garbage:
|
||||
; rdx: last processed digit
|
||||
; rsi: ptr to str final nullbyte+1
|
||||
; notes:
|
||||
; mul => rdx:rax = rax * r/m64
|
||||
stoi:
|
||||
mov rax, 0
|
||||
.stoi_parse_digit:
|
||||
cmp byte [rsi], 0
|
||||
je .stoi_return ; compare
|
||||
mul rdi ; shift radix
|
||||
|
||||
mov rdx, [rsi]
|
||||
and rdx, 0b1111 ; grab digit
|
||||
add rax, rdx ; add digit to the number
|
||||
inc rsi
|
||||
jmp .stoi_parse_digit
|
||||
.stoi_return:
|
||||
ret
|
||||
|
||||
; integer to string (idk how ppl name this, but I already got stoi)
|
||||
; takes:
|
||||
; rax: integer
|
||||
; rdi: radix
|
||||
; returns:
|
||||
; rsi: memory block (freeable when needed)
|
||||
; r10: start ptr (within block)
|
||||
; r9: str len
|
||||
; garbage:
|
||||
; rax: consumed integer
|
||||
; notes:
|
||||
; div => rdx:rax / r/m64 => rax(quot), rdx(remnd)
|
||||
itos:
|
||||
; save registers
|
||||
push rax
|
||||
push rdi
|
||||
; malloc some mem
|
||||
mov rax, 64 ; page size (max representable value is 64 bits long,
|
||||
; a full 64 bit register with radix 2)
|
||||
call malloc
|
||||
test rax, rax
|
||||
jnz .successful_malloc
|
||||
; allocation error likely?
|
||||
mov rsi, ERRMSG_MALLOC
|
||||
mov rdx, ERRMSG_MALLOC_LEN
|
||||
jmp errmsg
|
||||
.successful_malloc:
|
||||
mov rsi, rax ; put malloc'd mem into rsi
|
||||
; restore registers
|
||||
pop rdi
|
||||
pop rax
|
||||
|
||||
; align rsi ptr (we write from end)
|
||||
mov r10, rsi
|
||||
add r10, 64 ; we do an extra number cuz alignment and less intructs
|
||||
.itos_iter:
|
||||
dec r10
|
||||
mov rdx, 0 ; is used as upper half of divide, so set to 0
|
||||
div rdi ; now rax holds the new shifted result by default and we get
|
||||
; the remainder in rdx to shift into number range (higher
|
||||
; than 10 radix will work, but range of letters will be broken)
|
||||
add rdx, 48 ; '0' == 48
|
||||
mov byte [r10], dl ; lower(8) rdx
|
||||
test rax,rax ; gotta run at least once to at least get a zero when rax = 0
|
||||
jnz .itos_iter
|
||||
|
||||
.itos_return:
|
||||
mov r9, rsi
|
||||
add r9, 64
|
||||
sub r9, r10
|
||||
ret
|
||||
|
||||
print_r10_r9:
|
||||
print_last_itos:
|
||||
mov rax, OS_WRITE
|
||||
mov rdi, FD_STDOUT
|
||||
mov rsi, r10
|
||||
mov rdx, r9
|
||||
syscall
|
||||
ret
|
||||
Reference in New Issue
Block a user