AdventOfCode2022/4/day4.s
matthias@arch c079e80137 day 4
2022-12-05 14:24:14 +01:00

295 lines
11 KiB
ArmAsm

# Parts of this code were generated by OpenAI
# I did however have to modifiy nearly all of it
.data
count_contained:.long 0
count_overlap: .long 0
file: .quad 0 # file descriptor
line_length: .quad 0 # store the length of the current line in line_buffer
line_nr: .long 0 # store the line number
r1_upper: .long 0 # range 1 upper value
r2_upper: .long 0 # range 2 upper value
r1_lower: .long 0 # range 1 lower value
r2_lower: .long 0 # range 2 lower value
current_char: .long 0
filename: .asciz "section-pairs.txt"
format: .asciz "%d-%d,%d-%d"
f_contained: .asciz "Current line has containment. count_contained: [%d]\n"
f_res_cont: .asciz "The file contains %d lines where one of the two ranges contains the other\n"
f_res_over: .asciz "The file contains %d lines where one of the two ranges overlaps the other\n"
f_line_nr: .asciz "Line Nr: [%d] -\t"
f_line_length: .asciz "Line Length: [%d] -\tContent: '"
f_q_newline: .asciz "'\n"
f_error_open: .asciz "Error %d while opening file\n"
f_error_read: .asciz "Error %d while reading file.\n"
f_error_match: .asciz "Error %d while matching line.\n"
LINE_BUFSIZ = 32
PRINT_BUFSIZ = 100
SYS_READ = 0
SYS_WRITE = 1
SYS_OPEN = 2
SYS_CLOSE = 3
SYS_EXIT = 60
STDOUT = 1
.bss
line_buffer: .skip LINE_BUFSIZ
print_buffer: .skip PRINT_BUFSIZ
.text
.globl _start
.globl sscanfl
# syscall arg order
# (call #: rax) - rdi rsi rdx r10 r8 r9
_start:
push %rbp
mov %rsp, %rbp
# xorl %eax, %eax # initialize count_contained to 0
# movl $1, %ebx # initialize loop variable to 1
# open the file and store the file descriptor in %ecx
movq $SYS_OPEN, %rax # set the number of the "open" syscall
movq $filename, %rdi # move the address of the filename to %ebx
xorq %rsi, %rsi # set the flags to 0
xorq %rdx, %rdx # set the mode to 0 = read
# movq $777, %rsi
syscall
# if read fails, jump to error
jl .error_open
jg .error_open
# negative return value is error
cmpq $0, %rax
jl .error_open
movq %rax, file # store file descriptor in file
# read the file line by line
.loop:
call read_next_line
cmpq $0, %rax # rax is number of chars read, if 0 we are done
je .done
# get and print line lenght
movq %rax, line_length
# increment line nr
incl line_nr # increment line_nr
# print line nr
movl line_nr, %edx # load to print
leaq f_line_nr, %rsi # set print format
push %rdx
call print_rsi_rdx
pop %rdx
# print line lenght
movq line_length, %rdx
leaq f_line_length, %rsi
push %rdx
call print_rsi_rdx
pop %rdx
# print the line
movq $SYS_WRITE, %rax # set the number of the "write" syscall to 4
movq $STDOUT, %rdi # move the file descriptor (1 for stdout) to %ebx
movq $LINE_BUFSIZ, %rdx # number of bytes
leaq line_buffer, %rsi # buffer
syscall
# print newline
movq $SYS_WRITE, %rax # set the number of the "write" syscall to 4
movq $STDOUT, %rdi # move the file descriptor (1 for stdout) to %ebx
movq $2, %rdx # number of bytes
leaq f_q_newline, %rsi # buffer
syscall
# from first arg to last
leaq line_buffer, %rdi # Load the address of the line_buffer into %rdi
leaq format, %rsi # Move the address of the format string into %rs
leaq r1_lower, %rdx # Move the address of the first output register into %esi
leaq r1_upper, %rcx # Move the address of the second output register into %edx
leaq r2_lower, %r8 # Move the address of the third output register into %ecx
leaq r2_upper, %r9 # Move the address of the fourth output register into %r8d
push %rbx # to align the stack
call sscanf # Call the scanf function
pop %rbx # restore stack ptr
cmp $0, %rax
je .error_match # 0 is not succesful
# load the results into registers
movl r1_lower, %eax
movl r2_lower, %ebx
movl r1_upper, %ecx
movl r2_upper, %edx
cmp %ebx, %eax # compare r1l to r2l
jg .cont_r1l_greater_r2l
je .is_contained # if lower bounds are equal, one must be contained in the other
jl .cont_r1l_less_r2l
# 1) check containment
.cont_r1l_greater_r2l: # r1l > r2l
# to be contained: r1u <= r2u
cmp %edx, %ecx
jl .is_contained
je .is_contained
jmp .not_contained
.cont_r1l_less_r2l:
# to be contained: r1u >= r1u
cmp %edx, %ecx
jg .is_contained
je .is_contained
jmp .not_contained
movq $42, %rax
jmp .error_open # it should not come to this
.is_contained:
incl count_contained
jmp .overlaps # containment overlap
.not_contained:
# 2) overlap
# two ranges overlap if
# r1l > r2l:
# r1l <= r2u
# r1l < r2l:
# r1u >= r2l
# r1l == r2l
cmpl %ebx, %eax # compare r1l to r2l
jg .over_r1l_greater_r2l
je .overlaps
jl .over_r1l_less_r2l
movq $43, %rax
jmp .error_open # should not happen
.over_r1l_greater_r2l: # r1l > r2l
cmpl %edx, %eax # overlap if r1l <= r2u
je .overlaps
jl .overlaps
jmp .no_overlap
.over_r1l_less_r2l: # r1l < r2l
cmpl %ebx, %ecx # overlap if r1u >= r2l
jg .overlaps
je .overlaps
jmp .no_overlap
.overlaps:
incl count_overlap
.no_overlap:
jmp .loop # repeat the loop
.done:
movl count_contained, %edx
leaq f_res_cont, %rsi # set print format
push %rsi
call print_rsi_rdx
pop %rsi
movl count_overlap, %edx
leaq f_res_over, %rsi # set print format
push %rsi
call print_rsi_rdx
pop %rsi
movq $0, %r10 # set exit status
jmp .close_file
.error_open:
leaq f_error_open, %rsi # set print format
jmp .error
.error_read:
leaq f_error_read, %rsi # set print format
jmp .error
.error_match:
leaq f_error_match, %rsi # set print format
.error:
movq %rax, %rdx # print rax
# leaq f_error, %rsi # set print format
push %rax
call print_rsi_rdx
pop %rax
movq %rax, %r10 # set exit status
.close_file:
# close the file, expect exit status in %r10
movq $SYS_CLOSE, %rax # set the number of the "close" syscall to 3
movq file, %rdi # move the file descriptor to %rdi
syscall
leave
movq $SYS_EXIT, %rax
movq %r10, %rdi
syscall
read_next_line:
# read char by char, until newline or eof, return number of chars in rax
xorq %r10, %r10 # charcount_contained
xorq %rsi, %rsi # make sure rsi is 0
xorq %r11, %r11 # make sure r11 is 0
.load_char:
movq $SYS_READ, %rax # set the number of the "read" syscall
movq file, %rdi # move the file descriptor to %rdi
leaq current_char, %rsi # move the address of the charbuffer to %rsi
movq $1, %rdx # read only 1 char
syscall
jl .error_read
cmpq $0, %rax # if no char is loaded - eof
je .line_complete
movb current_char, %r11b
cmpb $'\n', %r11b # if newline
je .line_complete
movb %r11b, line_buffer(,%r10,1) # copy current char into the place at charcount_contained
incq %r10 # increment charcount_contained
jmp .load_char
.line_complete:
# null terminate the line
leaq line_buffer, %rax
movq $0, (%rax,%r10,1)
movq %r10, %rax # return number of chars loaded in rax
ret
print_rsi_rdx:
# print an int with $format, first get the formatted string from sprintf and the do a write syscall to stdout
# print the format string in %rsi which contains one int in %rdx
push %rdx # save the value
# Set up the format string and the integer value
leaq print_buffer, %rdi # Load the address of the buffer into %rdi
# Use sprintf to format the string and the integer value
call sprintf # Call the sprintf function
# Determine the number of bytes written to the buffer
movq %rax, %rdx # Move the number of bytes written to %rdx
# Set up the write syscall
movq $SYS_WRITE, %rax # set the number of the "write" syscall to 4
movq $STDOUT, %rdi # move the file descriptor (1 for stdout) to %ebx
leaq print_buffer, %rsi
syscall
pop %rdx
ret