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