diff --git a/fasm/.gitignore b/fasm/.gitignore new file mode 100644 index 0000000..44d4a10 --- /dev/null +++ b/fasm/.gitignore @@ -0,0 +1 @@ +problem \ No newline at end of file diff --git a/fasm/2015/1/problem.asm b/fasm/2015/1/problem.asm new file mode 100644 index 0000000..1148ce6 --- /dev/null +++ b/fasm/2015/1/problem.asm @@ -0,0 +1,275 @@ +format ELF64 executable 3 + +struc s_stat +{ + .st_dev dq 0 + .st_ino dq 0 + .st_nlink dq 0 + .st_mode dd 0 + .st_uid dd 0 + .st_gid dq 0 + .st_rdev dq 0 + .st_size dq 0 + .st_blksize dq 0 + .st_blocks dq 0 + .st_atim dq 0 + .st_atim_nano dq 0 + .st_mtim dq 0 + .st_mtim_nano dq 0 + .st_ctim dq 0 + .st_ctim_nano dq 0 + .st_atim_idk dq 0 + .st_mtim_idk dq 0 + .st_ctim_idk dq 0 +} + +macro syscall1 nr, arg1 +{ + mov rax, nr + mov rdi, arg1 + syscall +} + +macro syscall2 nr, arg1, arg2 +{ + mov rax, nr + mov rdi, arg1 + mov rsi, arg2 + syscall +} + +macro syscall3 nr, arg1, arg2, arg3 +{ + mov rax, nr + mov rdi, arg1 + mov rsi, arg2 + mov rdx, arg3 + syscall +} + +macro syscall6 nr, arg1, arg2, arg3, arg4, arg5, arg6 +{ + mov rax, nr + mov rdi, arg1 + mov rsi, arg2 + mov rdx, arg3 + mov r10, arg4 + mov r8, arg5 + mov r9, arg6 + syscall +} + +STDOUT equ 1 +STDERR equ 2 + +SYS_read equ 0 +;; ssize_t read(int fd, void buf[.count], size_t count); +macro read fd,buf,count +{ + syscall3 SYS_read, fd, buf, count +} + +SYS_write equ 1 +;; ssize_t write(int fd, const void buf[.count], size_t count); +macro write fd,buf,count +{ + syscall3 SYS_write, fd, buf, count +} + +SYS_open equ 2 +;; int open(const char *pathname, int flags); +macro open pathname, flags +{ + syscall2 SYS_open, pathname, flags +} + +SYS_close equ 3 +;; int close(int fd); +macro close fd +{ + syscall1 SYS_close, fd +} + +SYS_stat equ 4 +;; int stat(const char *restrict pathname +;; struct stat *restrict statbuf); +macro stat pathname, statbuf +{ + syscall2 SYS_stat, pathname, statbuf +} + + +PROT_READ equ 1 +MAP_PRIVATE = 2 +SYS_mmap equ 9 +;; void *mmap(void addr[.length], size_t length, int prot, int flags, +;; int fd, off_t offset); +macro mmap addr, length, prot, flags, fd, offset +{ + syscall6 SYS_mmap, addr, length, prot, flags, fd, offset +} + +SYS_munmap equ 11 +;; int munmap(void addr[.length], size_t length); +macro munmap addr, length +{ + syscall2 SYS_munmap, addr, length +} + +SYS_exit equ 60 +;; [[noreturn]] void _exit(int status); +macro exit status +{ + syscall1 SYS_exit, status +} + +segment readable executable +entry main + +main: + ;; Determine the file size of the input file + stat input_filename, file_stat + + ;; Open a file descriptor for the input file + open input_filename, 0 + mov [input_fd], rax + + ;; Map the input file into memory + mmap 0, [file_stat.st_size], PROT_READ, MAP_PRIVATE, [input_fd], 0 + mov [input], rax + + ;; Close the input file + close [input_fd] + + ;; Setup the loop variables for counting + ;; rbx starts at the first byte of input, and is incremented to read it all + mov rbx, [input] + ;; rcx tracks the current floor + mov rcx, 0 + ;; rdx counts down from the file's size to 0 + mov rdx, [file_stat.st_size] + +lp: + ;; Is the current character the "go up" character? + cmp byte [rbx], '(' + ;; If so, jump to "up" + je up + ;; If not, it's the "go down" character, so decrement the current floor + dec rcx + ;; Skip over the "increment" + jmp moved +up: + ;; We should "go up", so increment the current floor + inc rcx +moved: + ;; Check the next character in the file + inc rbx + ;; Count down the file's length + dec rdx + ;; If we haven't reached the end of the file, loop + jnz lp + + ;; Put part 1's answer in rax + mov rax, rcx + mov rbx, part_1 + call itoa + + ;; Write part 1's verbiage to STDOUT + write STDOUT, part_1_verbiage, 8 + write STDOUT, part_1, 6 + write STDOUT, newline, 1 + + ;; Setup the loop variables for counting + ;; rbx starts at the first byte of input, and is incremented to read it all + mov rbx, [input] + ;; rcx tracks the current floor + mov rcx, 0 + ;; rdx tracks how many steps we've made so far + mov rdx, 0 +lp2: + cmp byte [rbx], '(' + je up2 + dec rcx + jmp moved2 +up2: + inc rcx +moved2: + inc rdx + cmp rcx, 0 + jl done + inc rbx + jnz lp2 +done: + + ;; Put part 2's answer in rax + mov rax, rdx + mov rbx, part_2 + call itoa + + ;; Write part 2's verbiage to STDOUT + write STDOUT, part_2_verbiage, 8 + write STDOUT, part_2, 6 + write STDOUT, newline, 1 + + ;; Unmap the mapped file + munmap [input], [file_stat.st_size] + + ;; Done! + exit 0 + +;; rax contains the integer +;; rbx contains a pointer to the string buffer +itoa: + mov byte [rbx], 48 + mov byte [rbx + 1], 48 + mov byte [rbx + 2], 48 + mov byte [rbx + 3], 48 + mov byte [rbx + 4], 48 + mov byte [rbx + 5], 48 + sub rax, 100000 + inc byte [rbx] + cmp rax, 0 + jge itoa + add rax, 100000 + dec byte [rbx] +.ten_thousand: + sub rax, 10000 + inc byte [rbx + 1] + cmp rax, 0 + jge .ten_thousand + add rax, 10000 + dec byte [rbx + 1] +.one_thousand: + sub rax, 1000 + inc byte [rbx + 2] + cmp rax, 0 + jge .one_thousand + add rax, 1000 + dec byte [rbx + 2] +.one_hundred: + sub rax, 100 + inc byte [rbx + 3] + cmp rax, 0 + jge .one_hundred + add rax, 100 + dec byte [rbx + 3] +.ten: + sub rax, 10 + inc byte [rbx + 4] + cmp rax, 0 + jge .ten + add rax, 10 + dec byte [rbx + 4] + add [rbx + 5], rax + ret + +segment readable writable +input_filename db '../data/2015/1/input.txt', 0 +input_fd dq -1 +input dq -1 +part_1_verbiage db 'Part 1: ', 0 +part_1 db ' ', 0 +part_2_verbiage db 'Part 2: ', 0 +part_2 db ' ', 0 +newline db 10 +file_stat s_stat diff --git a/fasm/bin/fasm b/fasm/bin/fasm new file mode 100755 index 0000000..1cd2371 Binary files /dev/null and b/fasm/bin/fasm differ diff --git a/fasm/bin/run b/fasm/bin/run new file mode 100755 index 0000000..60303cd --- /dev/null +++ b/fasm/bin/run @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +year=$1 +day=$2 + +bin/fasm $year/$day/problem.asm $year/$day/problem && time ./$year/$day/problem \ No newline at end of file