aboutsummaryrefslogtreecommitdiff
path: root/snippets/utils.s
diff options
context:
space:
mode:
authorAndreas Kapp Lindquist <alind24@student.sdu.dk>2025-09-30 15:52:46 +0200
committermithe24 <mithe24@student.sdu.dk>2025-10-29 13:49:57 +0100
commit41c7279e634c1a9e9087d237ba316d13ecae2680 (patch)
tree5d50eab5fd879798ffec0a5e112974df97b06526 /snippets/utils.s
parent011fc5b69a8017624058e7dbdf2b6f06ab2a1dc2 (diff)
downloadsorter-41c7279e634c1a9e9087d237ba316d13ecae2680.tar.gz
sorter-41c7279e634c1a9e9087d237ba316d13ecae2680.zip
feat(utils.s): Added utils from lab sessions
Diffstat (limited to 'snippets/utils.s')
-rw-r--r--snippets/utils.s214
1 files changed, 214 insertions, 0 deletions
diff --git a/snippets/utils.s b/snippets/utils.s
new file mode 100644
index 0000000..f63d3f9
--- /dev/null
+++ b/snippets/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
+