From fa03afa46984fbf6eacbd5540e4e318d161cbbe0 Mon Sep 17 00:00:00 2001 From: mithe24 Date: Wed, 8 Oct 2025 13:35:41 +0200 Subject: chore(snippets): move snippetss to src/ --- snippets/allocate.s | 20 ----- snippets/fileHandling.s | 16 ---- snippets/parsing.s | 76 ----------------- snippets/utils.s | 214 ------------------------------------------------ src/lib/allocate.s | 21 +++++ src/lib/fileHandling.s | 16 ++++ src/lib/parsing.s | 76 +++++++++++++++++ src/lib/utils.s | 214 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 327 insertions(+), 326 deletions(-) delete mode 100644 snippets/allocate.s delete mode 100644 snippets/fileHandling.s delete mode 100644 snippets/parsing.s delete mode 100644 snippets/utils.s create mode 100644 src/lib/allocate.s create mode 100644 src/lib/fileHandling.s create mode 100644 src/lib/parsing.s create mode 100644 src/lib/utils.s diff --git a/snippets/allocate.s b/snippets/allocate.s deleted file mode 100644 index ef80957..0000000 --- a/snippets/allocate.s +++ /dev/null @@ -1,20 +0,0 @@ -# void *allocate(int n) -# -# A naive memory allocator that simply retrieves some new space from the OS. -# It is not possible to deallocate the memory again. -.globl allocate -.type allocate, @function -allocate: - push %rdi - # 1. Find the current end of the data segment. - movq $12, %rax # brk - xorq %rdi, %rdi # 0 means we retrieve the current end. - syscall - # 2. Add the amount of memory we want to allocate. - pop %rdi # the argument - push %rax # current end, which is where the allocated memory will start - addq %rax, %rdi # compute the new end - movq $12, %rax # brk - syscall - pop %rax # the old end, which is the address of our allocated memory - ret diff --git a/snippets/fileHandling.s b/snippets/fileHandling.s deleted file mode 100644 index 17a9428..0000000 --- a/snippets/fileHandling.s +++ /dev/null @@ -1,16 +0,0 @@ -# int getFileSize(int fd) -# -# Returns the size (in bytes) of the file indicated by the file descriptor. -.section .data -.Lstat: .space 144 # size of the fstat struct -.section .text -.globl getFileSize -.type getFileSize, @function -getFileSize: - movq $5, %rax # fstat - # rdi already contains the fd - movq $.Lstat, %rsi # buffer to write fstat data into - syscall - movq $.Lstat, %rax - movq 48(%rax), %rax # position of size in the struct - ret diff --git a/snippets/parsing.s b/snippets/parsing.s deleted file mode 100644 index e039be6..0000000 --- a/snippets/parsing.s +++ /dev/null @@ -1,76 +0,0 @@ -# int getLineCount(const char *data, int size) -# -# Returns the number of '\n' characters in the memory pointed to. -# 'data': the address of the first character to look at. -# 'size': the length of the memory area to scan through. -.globl getLineCount -.type getLinecount, @function -getLineCount: - # rdi: 'data' - # rsi: 'size' - addq %rdi, %rsi # make rsi the past-the-end pointer - xorq %rax, %rax # count = 0 -.LgetLineCount_loop: - cmpq %rdi, %rsi - je .LgetLineCount_end # if rdi == rsi: we are done - movb (%rdi), %dl # load the next byte - addq $1, %rdi - cmpb $0xA, %dl # is it a newline char? - jne .LgetLineCount_loop # if not, continue in the buffer - addq $1, %rax # completed a number - jmp .LgetLineCount_loop -.LgetLineCount_end: - ret - - -# void parseData(const char *data, int size, int *result) -# -# Converts the ASCII representation of the coordinates into pairs of numbers. -# 'data': the address of the first character in the ASCII representation. -# 'size': the length of the ASCII representation. -# 'result': the address of a piece of memory big enough to hold the -# coordinates. If there are n coordinates in the input, the 'result' -# memory will be an array of 2n 8-byte integers, with alternating x and y -# coordinates. -# -# Note, this functions only expects unsigned ints in the input and does not -# perform any validity checks at all. -.globl parseData -.type parseData, @function -parseData: - addq %rdi, %rsi # make rsi the past-the-end pointer - push %rsi # and store it as the top element on the stack -.LparseData_coordinateLoop: - cmpq (%rsp), %rdi - je .LparseData_coordinateLoop_end - movq $9, %rsi # '\t' - call parseNumber # increases rdi to point past-the-end of the number - movq %rax, (%rdx) # store the number - addq $8, %rdx # point to the next place for a number - movq $10, %rsi # '\n' - call parseNumber # increases rdi to point past-the-end of the number - movq %rax, (%rdx) # store the number - addq $8, %rdx # point to the next place for a number - jmp .LparseData_coordinateLoop -.LparseData_coordinateLoop_end: - addq $8, %rsp - ret - -# int parseNumber(const char *&data, const char *end) -parseNumber: - xorq %rax, %rax # result -.LparseNumber_loop: - xorq %r10, %r10 # the next digit - movb (%rdi), %r10b # read character - addq $1, %rdi # ++data - cmpq %rsi, %r10 # done with this number? - je .LparseNumber_loop_end - # here we assume that the character is actually a digit - # add this digit to the current number - subq $48, %r10 # convert the ASCII code to the digit it represents - imul $10, %rax # 'make room' for the new digit - addq %r10, %rax # and add the new digit - jmp .LparseNumber_loop -.LparseNumber_loop_end: - # we now have a number in rax - ret diff --git a/snippets/utils.s b/snippets/utils.s deleted file mode 100644 index f63d3f9..0000000 --- a/snippets/utils.s +++ /dev/null @@ -1,214 +0,0 @@ -# These registers are not neccesarily perserved after a function call: -# RAX RCX RDX RSI RDI R8 R9 R10 R11 -# Which means that these must be perserved: -# RBX RBP R12 R13 R14 R15 -# The order of arguments passed to functions is as follows: -# RDI RSI RDX RCX R8 R9 -# The order of the return registers is as follows: -# RAX RDX - -# Buffer for file data -.section .data -myBuffer: - .space 1 - -.section .text - - -# Print RDI as an unsigned integer following by a newline. -# Note: the function does not follow the ordinary calling convention, -# but restores all registers. -.type printNum, @function -.globl printNum -printNum: - push %rbp - movq %rsp, %rbp - - # save - push %rax - push %rdi - push %rsi - push %rdx - push %rcx - push %r8 - push %r9 - - movq %rdi, %rax # arg - - movq $1, %r9 # we always print "\n" - push $10 # '\n' -.LprintNum_convertLoop: - movq $0, %rdx - movq $10, %rcx - idivq %rcx - addq $48, %rdx # '0' is 48 - push %rdx - addq $1, %r9 - cmpq $0, %rax - jne .LprintNum_convertLoop -.LprintNum_printLoop: - movq $1, %rax # sys_write - movq $1, %rdi # stdout - movq %rsp, %rsi # buf - movq $1, %rdx # len - syscall - addq $8, %rsp - addq $-1, %r9 - jne .LprintNum_printLoop - - # restore - pop %r9 - pop %r8 - pop %rcx - pop %rdx - pop %rsi - pop %rdi - pop %rax - - movq %rbp, %rsp - pop %rbp - ret - -.globl intFromString # int intFromString(char *str) -# Pre: str != 0 -# Pre: all characters in the string are one of 0123456789. -.type intFromString, @function -intFromString: - xorq %rax, %rax -.LintFromString_loop: - movzx (%rdi), %rsi # Move a single character/byte %rbx and zero-extend it. - cmpq $0, %rsi # A string ends with a 0-byte. - je .LintFromString_done - movq $10, %rcx # Shift the number 1 decimal place to the left. - mulq %rcx - subq $48, %rsi # Convert from ASCII character to number. ASCII '0' has value 48. '1' is 49, etc. - addq %rsi, %rax # Add the number. - addq $1, %rdi - jmp .LintFromString_loop -.LintFromString_done: - ret - - -# The pointer to the string is argument RDI -# It is required that the string ends with the zero byte -.type printString, @function -.globl printString -printString: - push %r12 # Save R12 - - movq %rdi, %r12 # Save copy of string address - call stringLength # Get length of string in RAX - - movq $1, %rdi # Select to write to stdout - movq %r12, %rsi # Use pointer at start of string - movq %rax, %rdx # Put string size in rdx - movq $1, %rax # Select sys_write - syscall # Call the function - - pop %r12 # Restore R12 - ret - - -# Requires that the file is already open, and file descriptor is passed as first -# argument. -.type printFile, @function -.globl printFile -printFile: - # The callee-saved registers - push %rbx - push %rbp - push %r12 - push %r13 - push %r14 - push %r15 - - movq %rdi, %r10 # Save file descriptor in r10 - -loop: - movq %r10, %rdi # Select the file discriptor - movq $0, %rax # Select read syscall - movq $1, %rdx # Size to read from file - movq $myBuffer, %rsi # Select the buffer to store input - syscall # Read from the file - - cmp $0, %rax # If rax is zero, end of file - je endPrintFile # Jump to end of program - - movq $1, %rdx # Put string size in RDX - movq $myBuffer, %rsi # Use pointer at start of string - movq $1, %rdi # Select to write to stdout - movq $1, %rax # Select sys_write - syscall # Call the function - - jmp loop - -endPrintFile: - # The callee-saved registers - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp - pop %rbx - - ret - - -.type printStdin, @function -.globl printStdin -printStdin: - # The callee-saved registers - push %rbx - push %rbp - push %r12 - push %r13 - push %r14 - push %r15 - -printStdinLoop: - movq $0, %rax # Select read syscall - movq $1, %rdx # Size to read - movq $0, %rdi # Select stdin - movq $myBuffer, %rsi # Select the buffer to store input - syscall - - cmp $0, %rax # Check if there was something to be read. - je endPrintStdin # If not, jump to end - - movq $1, %rdx # Put string size in rdx - movq $myBuffer, %rsi # Use pointer at start of string - movq $1, %rdi # Select to write to stdout - movq $1, %rax # Select sys_write - syscall # Call the function - - jmp printStdinLoop - - -endPrintStdin: - # The callee-saved registers - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp - pop %rbx - - ret - -.type stringLength, @function -.globl stringLength -stringLength: - movq $0, %rcx # CL will keep the current byte - movq $0, %rax # The length counter - -loopStringLength: - movb (%rdi), %cl # Move the lower byte of the string into CL - cmp $0, %cl # Compare 0 with the lower byte of register C - je endStringLength # Go the end - addq $1, %rax # Add one to length - addq $1, %rdi # Go one forward in address - jmp loopStringLength# Go to start of loop - -endStringLength: - ret - diff --git a/src/lib/allocate.s b/src/lib/allocate.s new file mode 100644 index 0000000..fdd9bf8 --- /dev/null +++ b/src/lib/allocate.s @@ -0,0 +1,21 @@ +# void *allocate(int n) +# +# A naive memory allocator that simply retrieves some new space from the OS. +# It is not possible to deallocate the memory again. +.globl allocate +.type allocate, @function +allocate: + push %rdi + # 1. Find the current end of the data segment. + movq $12, %rax # brk + xorq %rdi, %rdi # 0 means we retrieve the current end. + syscall + # 2. Add the amount of memory we want to allocate. + pop %rdi # the argument + push %rax # current end, which is where the allocated memory will start + addq %rax, %rdi # compute the new end + movq $12, %rax # brk + syscall + pop %rax # the old end, which is the address of our allocated memory + ret + diff --git a/src/lib/fileHandling.s b/src/lib/fileHandling.s new file mode 100644 index 0000000..17a9428 --- /dev/null +++ b/src/lib/fileHandling.s @@ -0,0 +1,16 @@ +# int getFileSize(int fd) +# +# Returns the size (in bytes) of the file indicated by the file descriptor. +.section .data +.Lstat: .space 144 # size of the fstat struct +.section .text +.globl getFileSize +.type getFileSize, @function +getFileSize: + movq $5, %rax # fstat + # rdi already contains the fd + movq $.Lstat, %rsi # buffer to write fstat data into + syscall + movq $.Lstat, %rax + movq 48(%rax), %rax # position of size in the struct + ret diff --git a/src/lib/parsing.s b/src/lib/parsing.s new file mode 100644 index 0000000..e039be6 --- /dev/null +++ b/src/lib/parsing.s @@ -0,0 +1,76 @@ +# int getLineCount(const char *data, int size) +# +# Returns the number of '\n' characters in the memory pointed to. +# 'data': the address of the first character to look at. +# 'size': the length of the memory area to scan through. +.globl getLineCount +.type getLinecount, @function +getLineCount: + # rdi: 'data' + # rsi: 'size' + addq %rdi, %rsi # make rsi the past-the-end pointer + xorq %rax, %rax # count = 0 +.LgetLineCount_loop: + cmpq %rdi, %rsi + je .LgetLineCount_end # if rdi == rsi: we are done + movb (%rdi), %dl # load the next byte + addq $1, %rdi + cmpb $0xA, %dl # is it a newline char? + jne .LgetLineCount_loop # if not, continue in the buffer + addq $1, %rax # completed a number + jmp .LgetLineCount_loop +.LgetLineCount_end: + ret + + +# void parseData(const char *data, int size, int *result) +# +# Converts the ASCII representation of the coordinates into pairs of numbers. +# 'data': the address of the first character in the ASCII representation. +# 'size': the length of the ASCII representation. +# 'result': the address of a piece of memory big enough to hold the +# coordinates. If there are n coordinates in the input, the 'result' +# memory will be an array of 2n 8-byte integers, with alternating x and y +# coordinates. +# +# Note, this functions only expects unsigned ints in the input and does not +# perform any validity checks at all. +.globl parseData +.type parseData, @function +parseData: + addq %rdi, %rsi # make rsi the past-the-end pointer + push %rsi # and store it as the top element on the stack +.LparseData_coordinateLoop: + cmpq (%rsp), %rdi + je .LparseData_coordinateLoop_end + movq $9, %rsi # '\t' + call parseNumber # increases rdi to point past-the-end of the number + movq %rax, (%rdx) # store the number + addq $8, %rdx # point to the next place for a number + movq $10, %rsi # '\n' + call parseNumber # increases rdi to point past-the-end of the number + movq %rax, (%rdx) # store the number + addq $8, %rdx # point to the next place for a number + jmp .LparseData_coordinateLoop +.LparseData_coordinateLoop_end: + addq $8, %rsp + ret + +# int parseNumber(const char *&data, const char *end) +parseNumber: + xorq %rax, %rax # result +.LparseNumber_loop: + xorq %r10, %r10 # the next digit + movb (%rdi), %r10b # read character + addq $1, %rdi # ++data + cmpq %rsi, %r10 # done with this number? + je .LparseNumber_loop_end + # here we assume that the character is actually a digit + # add this digit to the current number + subq $48, %r10 # convert the ASCII code to the digit it represents + imul $10, %rax # 'make room' for the new digit + addq %r10, %rax # and add the new digit + jmp .LparseNumber_loop +.LparseNumber_loop_end: + # we now have a number in rax + ret diff --git a/src/lib/utils.s b/src/lib/utils.s new file mode 100644 index 0000000..f63d3f9 --- /dev/null +++ b/src/lib/utils.s @@ -0,0 +1,214 @@ +# These registers are not neccesarily perserved after a function call: +# RAX RCX RDX RSI RDI R8 R9 R10 R11 +# Which means that these must be perserved: +# RBX RBP R12 R13 R14 R15 +# The order of arguments passed to functions is as follows: +# RDI RSI RDX RCX R8 R9 +# The order of the return registers is as follows: +# RAX RDX + +# Buffer for file data +.section .data +myBuffer: + .space 1 + +.section .text + + +# Print RDI as an unsigned integer following by a newline. +# Note: the function does not follow the ordinary calling convention, +# but restores all registers. +.type printNum, @function +.globl printNum +printNum: + push %rbp + movq %rsp, %rbp + + # save + push %rax + push %rdi + push %rsi + push %rdx + push %rcx + push %r8 + push %r9 + + movq %rdi, %rax # arg + + movq $1, %r9 # we always print "\n" + push $10 # '\n' +.LprintNum_convertLoop: + movq $0, %rdx + movq $10, %rcx + idivq %rcx + addq $48, %rdx # '0' is 48 + push %rdx + addq $1, %r9 + cmpq $0, %rax + jne .LprintNum_convertLoop +.LprintNum_printLoop: + movq $1, %rax # sys_write + movq $1, %rdi # stdout + movq %rsp, %rsi # buf + movq $1, %rdx # len + syscall + addq $8, %rsp + addq $-1, %r9 + jne .LprintNum_printLoop + + # restore + pop %r9 + pop %r8 + pop %rcx + pop %rdx + pop %rsi + pop %rdi + pop %rax + + movq %rbp, %rsp + pop %rbp + ret + +.globl intFromString # int intFromString(char *str) +# Pre: str != 0 +# Pre: all characters in the string are one of 0123456789. +.type intFromString, @function +intFromString: + xorq %rax, %rax +.LintFromString_loop: + movzx (%rdi), %rsi # Move a single character/byte %rbx and zero-extend it. + cmpq $0, %rsi # A string ends with a 0-byte. + je .LintFromString_done + movq $10, %rcx # Shift the number 1 decimal place to the left. + mulq %rcx + subq $48, %rsi # Convert from ASCII character to number. ASCII '0' has value 48. '1' is 49, etc. + addq %rsi, %rax # Add the number. + addq $1, %rdi + jmp .LintFromString_loop +.LintFromString_done: + ret + + +# The pointer to the string is argument RDI +# It is required that the string ends with the zero byte +.type printString, @function +.globl printString +printString: + push %r12 # Save R12 + + movq %rdi, %r12 # Save copy of string address + call stringLength # Get length of string in RAX + + movq $1, %rdi # Select to write to stdout + movq %r12, %rsi # Use pointer at start of string + movq %rax, %rdx # Put string size in rdx + movq $1, %rax # Select sys_write + syscall # Call the function + + pop %r12 # Restore R12 + ret + + +# Requires that the file is already open, and file descriptor is passed as first +# argument. +.type printFile, @function +.globl printFile +printFile: + # The callee-saved registers + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + movq %rdi, %r10 # Save file descriptor in r10 + +loop: + movq %r10, %rdi # Select the file discriptor + movq $0, %rax # Select read syscall + movq $1, %rdx # Size to read from file + movq $myBuffer, %rsi # Select the buffer to store input + syscall # Read from the file + + cmp $0, %rax # If rax is zero, end of file + je endPrintFile # Jump to end of program + + movq $1, %rdx # Put string size in RDX + movq $myBuffer, %rsi # Use pointer at start of string + movq $1, %rdi # Select to write to stdout + movq $1, %rax # Select sys_write + syscall # Call the function + + jmp loop + +endPrintFile: + # The callee-saved registers + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + + ret + + +.type printStdin, @function +.globl printStdin +printStdin: + # The callee-saved registers + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + +printStdinLoop: + movq $0, %rax # Select read syscall + movq $1, %rdx # Size to read + movq $0, %rdi # Select stdin + movq $myBuffer, %rsi # Select the buffer to store input + syscall + + cmp $0, %rax # Check if there was something to be read. + je endPrintStdin # If not, jump to end + + movq $1, %rdx # Put string size in rdx + movq $myBuffer, %rsi # Use pointer at start of string + movq $1, %rdi # Select to write to stdout + movq $1, %rax # Select sys_write + syscall # Call the function + + jmp printStdinLoop + + +endPrintStdin: + # The callee-saved registers + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + + ret + +.type stringLength, @function +.globl stringLength +stringLength: + movq $0, %rcx # CL will keep the current byte + movq $0, %rax # The length counter + +loopStringLength: + movb (%rdi), %cl # Move the lower byte of the string into CL + cmp $0, %cl # Compare 0 with the lower byte of register C + je endStringLength # Go the end + addq $1, %rax # Add one to length + addq $1, %rdi # Go one forward in address + jmp loopStringLength# Go to start of loop + +endStringLength: + ret + -- cgit v1.2.3-70-g09d2