Skip to content

Instantly share code, notes, and snippets.

@Yepoleb
Last active December 5, 2020 22:45
Show Gist options
  • Save Yepoleb/09ab9339dbe1acb2ee11e6c7b6ea7890 to your computer and use it in GitHub Desktop.
Save Yepoleb/09ab9339dbe1acb2ee11e6c7b6ea7890 to your computer and use it in GitHub Desktop.
# Compile: gcc aoc_day1.s -nostdlib -fPIC -o aoc_day1
.intel_syntax noprefix
.data
.section .rodata
filename:
.string "input_1.txt"
errormsg_open:
.string "Failed to open file\n"
.set errormsg_open_len, . - errormsg_open - 1
successmsg_open:
.string "Successfully opened file!\n"
.set successmsg_open_len, . - successmsg_open - 1
errormsg_read:
.string "Read failed\n"
.set errormsg_read_len, . - errormsg_read - 1
newline:
.string "\n"
.bss
ibuffer_fd:
.skip 8
ibuffer_size:
.skip 8
ibuffer_pos:
.skip 8
.set ibuffer_maxsize, 1024
ibuffer:
.skip ibuffer_maxsize
values:
.skip 200 * 8
.set values_maxsize, 200 * 8
.text
# Parameters: msg:rdi, msg_len:rsi
write_stdout:
mov rdx, rsi # count = msg_len
mov rsi, rdi # buf = msg
mov rax, 1 # write
mov rdi, 1 # stdout
syscall
ret
# Like write_stdout but adds a newline
# Parameters: msg:rdi, msg_len:rsi
print_stdout:
call write_stdout
lea rdi, [rip + newline]
mov rsi, 1
call write_stdout
# Parameters: msg:rdi, msg_len:rsi
quit_with_error:
mov rdx, rsi # count = msg_len
mov rsi, rdi # buf = msg
mov rax, 1 # write
mov rdi, 2 # stderr
syscall
mov rax, 60 # exit
mov rdi, 1 # returncode
syscall
# Parameters: line_ptr:rdi
# Returns: line_end:rax, eof:rdx
get_line:
push r12
mov r12, rdi # line_pos_ptr
get_line_loop:
call get_byte # char:rax, eof:rdx
test rdx, rdx # if eof: return
jnz get_line_return
cmp rax, 0x0A # if \n: return
je get_line_return
mov byte ptr [r12], al # set char
inc r12
jmp get_line_loop
get_line_return:
mov rax, r12
pop r12
ret
# Returns: byte:rax, eof:rdx
get_byte:
mov r8, [rip + ibuffer_pos]
mov r9, [rip + ibuffer_size]
lea r10, [rip + ibuffer]
cmp r8, r9
jb get_byte_buffer_healthy # pos < size
# refresh buffer
mov rax, 0 # read
mov rdi, [rip + ibuffer_fd] # fd
mov rsi, r10 # buf = ibuffer
mov rdx, ibuffer_maxsize # count
syscall # bytes_read/errno:rax
cmp rax, 0
jl get_byte_read_failed
je get_byte_return_eof
mov r9, rax # ibuffer_size = return value
mov [rip + ibuffer_size], r9 # write back to memory
mov r8, 0 # ibuffer_pos = 0
get_byte_buffer_healthy:
movzx rax, byte ptr [r10 + r8] # ibuffer + ibuffer_pos
inc r8 # ibuffer_pos++
mov [rip + ibuffer_pos], r8 # write back to memory
mov rdx, 0
ret
get_byte_return_eof:
mov rax, 0
mov rdx, 1
ret
get_byte_read_failed:
lea rdi, [rip + errormsg_read]
mov rsi, errormsg_read_len
jmp quit_with_error
# Parameters: string_begin:rdi, string_end:rsi
# Returns: value:rax
parse_int:
mov rax, 0
parse_int_loop:
cmp rdi, rsi
jge parse_int_return
imul rax, rax, 10 # Multiply rax by 10
movzx rdx, byte ptr [rdi]
add rdx, -'0' # Subtract char value of '0'
add rax, rdx # Add digit value
inc rdi
jmp parse_int_loop
parse_int_return:
ret
# Parameters: intval:rdi, buffer_start:rsi
# Returns: buffer_end:rax
format_int:
mov r8, rsi # buffer_end = buffer_start
mov rax, rdi # remval = intval
format_int_digits_loop:
test rax, rax
jz format_int_digits_end
mov rdx, 0 # clear rdx for division
mov rcx, 10
div rcx # rax = remval / 10, rdx = remval % 10
add rdx, '0' # Add char value of '0'
mov byte ptr [r8], dl # Write character to buffer
inc r8
jmp format_int_digits_loop
format_int_digits_end:
# Reverse digits
mov r9, rsi # pos_low = buffer_start
mov rax, r8 # Move buffer_end to return variable so r8 can become pos_high
add r8, -1 # subtract 1 from end to point at last character
format_int_reverse_loop:
cmp r9, r8
jge format_int_reverse_end # if pow_low >= pos_high: break
mov cl, byte ptr [r8] # exchange values
mov dl, byte ptr [r9]
mov byte ptr [r9], cl
mov byte ptr [r8], dl
inc r9 # increase/decrease pointers
dec r8
jmp format_int_reverse_loop
format_int_reverse_end:
ret
.global _start
_start:
# Open input file
mov rax, 2 # open
lea rdi, [rip + filename]
mov rsi, 0 # flags
mov rdx, 0 # mode read
syscall
mov [rip + ibuffer_fd], rax
cmp rax, 0
jle open_failed
# Print success message
lea rdi, [rip + successmsg_open]
mov rsi, successmsg_open_len
call write_stdout
# Read input values
lea r12, [rip + values] # values_pos:r12 = &values
sub rsp, 32 # rsp = line_begin
input_loop:
mov rdi, rsp
call get_line # line_end:rax, eof:rdx
test rdx, rdx # if eof
jnz input_loop_end
# Output line
#mov rdi, rsp
#mov rsi, rax
#sub rsi, rsp # calculate length
#call print_stdout
mov rdi, rsp
mov rsi, rax
call parse_int # parse_int(line_begin, line_end) -> rax
mov qword ptr [r12], rax
add r12, 8
jmp input_loop
input_loop_end:
lea r10, [rip + values] # i_pos
outer_loop:
cmp r10, r12 # while i_pos < values_end
jge outer_loop_end
mov r11, r10
inner_loop:
cmp r11, r12 # while j_pos < values_end
jge inner_loop_end
mov r13, qword ptr [r10] # ival
mov r14, qword ptr [r11] # jval
mov rcx, r13
add rcx, r14
cmp rcx, 2020
je outer_loop_end
add r11, 8
jmp inner_loop
inner_loop_end:
add r10, 8
jmp outer_loop
outer_loop_end:
# ival:r13, jval:r14
# repurposing input line buffer for output
mov r15, r13
imul r15, r14 # ival*jval:r15
mov rsi, rsp # line_pos
mov rdi, r13
call format_int # format_int(ival, line_pos) -> line_pos:rax
mov byte ptr [rax], ' '
lea rsi, [rax + 1]
mov rdi, r14
call format_int
mov byte ptr [rax], ' '
lea rsi, [rax + 1]
mov rdi, r15
call format_int
mov byte ptr [rax], '\n'
mov rdi, rsp
lea rsi, [rax + 1]
sub rsi, rdi # calculate string length
call write_stdout
add rsp, 32 # delete line buffer
mov rax, 60 # exit
mov rdi, 0
syscall
open_failed:
lea rdi, [rip + errormsg_open]
mov rsi, errormsg_open_len
jmp quit_with_error
# Does not fully match the final code, but the general concepts are the same
MAX_BUFFERSIZE = 5
class FileStream:
def __init__(self, fd):
self.fd = fd
self.buffer = b""
self.buffer_size = 0
self.index = 0
def refreshBuffer(self):
self.buffer = self.fd.read(MAX_BUFFERSIZE)
self.buffer_size = len(self.buffer)
if not self.buffer_size:
return True
self.index = 0
return False
def getByte(self):
if self.index >= self.buffer_size:
eof = self.refreshBuffer()
if eof:
return ("\0", True)
b = self.buffer[self.index]
self.index += 1
return (b, False)
def readLine(stream):
line = ""
while True:
char, eof = stream.getByte()
if eof:
return (line, True)
if char == "\n":
return (line, False)
line += char
def parseInt(int_str):
val = 0
for i in range(len(int_str)):
val = val * 10 + ord(int_str[i]) - ord("0")
return val
def reverse(l):
pos_low = 0
pos_high = len(l) - 1
while pos_low < pos_high:
t1 = l[pos_low]
t2 = l[pos_high]
l[pos_low] = t2
l[pos_high] = t1
pos_low += 1
pos_high -= 1
def formatInt(intval):
remval = intval
digits_reversed = []
while remval:
digit_val = remval % 10
remval = remval // 10
digits_reversed.append(chr(ord("0") + digit_val))
reverse2(digits_reversed)
return "".join(digits_reversed)
class DynamicIntArray:
def __init__(self, mem, memsize):
self.mem = mem
self.memsize = memsize
self.size = 0
def append(self, value):
assert self.size < self.memsize
self.mem[self.size] = value
self.size += 1
def __getitem__(self, index):
return self.mem[index]
values = DynamicIntArray([0] * 200, 200)
f = open("input_1.txt")
stream = FileStream(f)
while True:
line, eof = stream.readLine()
if eof:
break
value = parseInt(line)
values.append(value)
for i in range(values.size):
for j in range(i, values.size):
ival = values[i]
jval = values[j]
if ival + jval == 2020:
print(formatInt(ival), formatInt(jval), formatInt(ival * jval))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment