Skip to content

Instantly share code, notes, and snippets.

@bysse
Last active December 1, 2020 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bysse/28f2d99f789b9b1e483ff57517a29175 to your computer and use it in GitHub Desktop.
Save bysse/28f2d99f789b9b1e483ff57517a29175 to your computer and use it in GitHub Desktop.
AdventOfCode 2020 day 1 - 64bit assembly no libc
DEFAULT REL
global main
SECTION .data
filename:
db "day1.txt", 0h
SECTION .bss
numbers: dq 0,0,0,0,0,0,0,0
lines: dq 0,0,0,0,0,0,0,0
filebuffer_size: dw 0,0,0,0
numberbuffer_size: dw 0,0,0,0
result_a: dw 0,0,0,0
result_b: dw 0,0,0,0
SECTION .text
main:
push rbp
; load the input
mov rdi, filename
call load_file
cmp rax, 0 ; exit if bytes read is 0
jz exit
mov [filebuffer_size], eax ; store the number of bytes allocated
; count how many lines the file has
mov rax, [filebuffer]
mov rcx, 0
size_loop:
mov rbx, [rax]
cmp bl, 10
jnz size_loop_skip
inc rcx
size_loop_skip:
inc rax
dec rdx
ja size_loop
mov [lines], rcx ; number of lines
; allocate memory for 64 bit numbers
imul rdi, rcx, 8
mov [numberbuffer_size], edi; store the number of bytes allocated
call allocate
mov [numbers], rax
; parse the numbers
mov r12, [filebuffer] ; current char
mov rcx, [lines] ; number of lines
mov rdx, [numbers] ; destination buffer
mov rdi, r12 ; start of current number
dec r12
parse_loop: ; find the end of line
inc r12
mov rbx, [r12]
cmp bl, 10
jnz parse_loop
mov [r12], byte 0 ; write EOL
cmp rdi, rdx
jz skip_parsing
; parse the string to a number
push rdx
push rcx
call to_int
pop rcx
pop rdx
; store the number in memory
mov [rdx], rax
add rdx, 8
skip_parsing:
inc r12 ; move to the next char
mov rdi, r12 ; store the start of the number
dec rcx
ja parse_loop
; calculate numbers
xor rax, rax
mov [result_a], rax
mov [result_b], rax
mov r10, [lines] ; i
mov r11, [lines] ; j
dec r10
dec r11
part_a_loop:
dec r11
; calculate part a
mov rdx, [numbers] ; source buffer
lea rcx, [rdx + 8*r10] ; load next address for i
lea rdx, [rdx + 8*r11] ; load next address for j
mov rax, [rcx]
mov rbx, [rdx]
mov rcx, rax ; copy of number[i]
add rax, rbx ; sum the numbers
cmp rax, 2020
jne not_part_a
imul rcx, rbx ; calculate the product
mov [result_a], rcx
not_part_a:
cmp [result_b], dword 0 ; skip calculation if we already have a result
jnz end_of_b
mov r15, rax ; store sum in r11
; calculate part b
mov r12, [lines] ; k
dec r12
part_b_loop:
lea r13, [rdx + 8*r12] ; load address for k
mov r14, [r13] ; k in r14
mov rax, r14
add rax, r15
cmp rax, 2020 ; sum and compare
jne not_part_b
mov rax, r14
imul rax, rbx
imul rax, rcx
mov [result_b], rax ; calculate the product
not_part_b:
dec r12
jnz part_b_loop ; loop while k > 0
end_of_b:
cmp r11, 0
jnz part_a_loop ; loop while j > 0
dec r10 ; decrease i
mov r11, r10 ; set j = i
cmp r10, 0
jnz part_a_loop ; loop while i > 0
; output result A
mov rdi, [result_a]
call output_number
; output result B
mov rdi, [result_b]
call output_number
; free the memory buffers
xor rsi, rsi
mov rdi, [filebuffer]
mov esi, [filebuffer_size]
call de_allocate
mov rdi, [numbers]
mov esi, [numberbuffer_size]
call de_allocate
exit:
pop rbp
mov ebx, 0
mov eax, 1
int 80h
%include 'io.asm'
%define SYS_READ 0
%define SYS_WRITE 1
%define SYS_OPEN 2
%define SYS_CLOSE 3
%define SYS_STAT 4
%define SYS_MMAP 9
%define SYS_MUNMAP 11
%define O_RDONLY 0
%define PROT_READ 4
%define PROT_WRITE 2
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
struc STAT
.st_dev resq 1
.st_ino resq 1
.st_nlink resq 1
.st_mode resd 1
.st_uid resd 1
.st_gid resd 1
.pad0 resb 4
.st_rdev resq 1
.st_size resq 1
.st_blksize resq 2
.st_time resq 6
endstruc
SECTION .data
filebuffer: dq 0,0,0,0,0,0,0,0
SECTION .bss
%define sizeof(x) x %+ _size
stat_buffer: db sizeof(STAT)
SECTION .text
; filename in rdi
load_file:
; get size of file
push rbp
push rdi
push rdi ; store filename on the stack twice
mov rax, SYS_STAT ; stat the file
pop rdi
mov rsi, stat_buffer
syscall
cmp rax, 0
jnz load_file_error
; allocate memory file size
mov rdi, [stat_buffer + STAT.st_size]
call allocate
mov [filebuffer], rax
; open file
mov rax, SYS_OPEN
pop rdi
mov rsi, O_RDONLY
mov rdx, 0 ; mode = 0
syscall
cmp rax, 0
jle load_file_error
mov r8, rax ; store file descriptor
; read from file
mov rax, SYS_READ
mov rdi, r8
mov rsi, [filebuffer]
mov rdx, [stat_buffer + STAT.st_size]
syscall
; close the file
mov rax, SYS_CLOSE
mov rdi, r8
syscall
cmp rax, 0
jnz load_file_error
; prepare the return value
mov rax, [stat_buffer + STAT.st_size]
pop rbp
ret
load_file_error:
; prepare the return value
xor rax, rax
pop rbp
ret
; allocate memory - size in rdi
allocate:
push r11
push r10
push r9
push r8
push rdx
push rcx
mov rax, SYS_MMAP
mov rsi, rdi
mov rdi, 0 ; addr = NULL
mov rdx, PROT_READ | PROT_WRITE
mov r10, MAP_PRIVATE | MAP_ANONYMOUS
mov r8, -1
mov r9, 0
syscall
pop rcx
pop rdx
pop r8
pop r9
pop r10
pop r11
ret
; deallocate memory - rdi (addr), rdi (length)
de_allocate:
mov rax, SYS_MUNMAP
syscall
ret
; convert a string to number - rdi (string)
to_int:
mov rax, 1 ; power
mov r8, 0 ; length
mov r10, 0 ; result
mov rsi, rdi ; string
ti_length_loop:
mov rbx, [rsi]
cmp bl, 0
jz ti_calc_loop
imul rax, rax, 10
inc rsi
inc r8
jmp ti_length_loop
ti_calc_loop:
mov rbx, [rdi]
cmp bl, 0 ; check exit condition
jz ti_calc_exit
mov rcx, 10 ; power /= 10
xor rdx, rdx
idiv rcx
xor rdx, rdx
mov dl, bl
sub rdx, 48 ; digit - '0'
imul rdx, rax ; *= power
add r10, rdx ; add to result
inc rdi ; next character
dec r8
jnz ti_calc_loop
ti_calc_exit:
mov rax, r10
ret
; convert a number to a string - rdi (number)
output_number:
mov r8, 2 ; length, 2 because of \n and the null termination
mov r9, rdi ; number
mov r10, 1 ; power
mov r11, 0 ; negative
cmp rdi, 0
jge on_length_loop
neg rdi ; invert the number to a positive one
mov r11, 1 ; indicate that the number is negative
on_length_loop:
cmp r10, rdi
jge on_length_exit
imul r10, r10, 10
inc r8
jmp on_length_loop
on_length_exit:
add r8, r11 ; adjust length for - sign
; allocate memory for the string
mov rdi, r8
call allocate
mov r12, rax ; start of memory in r12
mov rsi, rax ; current char in rsi
; adjust the power
mov rax, r10
mov rcx, 10 ; power /= 10
xor rdx, rdx
idiv rcx
mov r10, rax
; add the minus sign
cmp r11, 0
jz on_positive_number
mov [rsi], byte 45 ; '-'
inc rsi
on_positive_number:
mov rax, r9 ; number
mov rdi, r8 ; length
sub rdi, 2
on_fill_buffer_loop:
; divide the number by power
mov rcx, r10
xor rdx, rdx
cmp rax, 0
jz on_zero
idiv rcx
on_zero:
mov r14, rdx ; reminder
add al, 48 ; '0' + div
mov [rsi], byte al ; write the character
; lower the power
mov rax, r10
mov rcx, 10 ; power /= 10
xor rdx, rdx
idiv rcx
mov r10, rax
; exit condition
mov rax, r14 ; use the reminder for the next loop
inc rsi ; next char
dec rdi
jnz on_fill_buffer_loop
mov [rsi], word 0x000a ; add new line and null termination
on_print:
; print the buffer
mov rax, SYS_WRITE
mov rdi, 1 ; stdout
mov rsi, r12
mov rdx, r8
syscall
; deallocate the buffer
mov rdi, r12
mov rsi, r8
call de_allocate
ret
day1: build/day1.o
ld -s build/day1.o -o day1
build/%.o: %.asm build
nasm -f elf64 -o $@ $<
build:
mkdir -p build
clean:
rm -rf build day1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment