# 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