From 41c7279e634c1a9e9087d237ba316d13ecae2680 Mon Sep 17 00:00:00 2001 From: Andreas Kapp Lindquist Date: Tue, 30 Sep 2025 15:52:46 +0200 Subject: feat(utils.s): Added utils from lab sessions --- snippets/utils.s | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 snippets/utils.s 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 + -- cgit v1.2.3-70-g09d2