From d98f46ce647846b0aa30b2e16a30fd4e152a1bf5 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Thu, 10 Jul 2025 22:55:07 +0200 Subject: Add new code Signed-off-by: Carlos Maiolino --- PGU/CHAP5/toupper.s | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 PGU/CHAP5/toupper.s (limited to 'PGU/CHAP5/toupper.s') diff --git a/PGU/CHAP5/toupper.s b/PGU/CHAP5/toupper.s new file mode 100644 index 0000000..b3f4f13 --- /dev/null +++ b/PGU/CHAP5/toupper.s @@ -0,0 +1,206 @@ +# Convert an input file to an output file with all +# letters converted to uppercase + +.section .data + +# CONSTANTS +.equ SYS_OPEN, 2 +.equ SYS_WRITE, 1 +.equ SYS_READ, 0 +.equ SYS_CLOSE, 3 +.equ SYS_EXIT, 60 + +# We have no access to headers, so, let's define our flags +.equ O_RDONLY, 0 +.equ O_CREAT_WRONLY_TRUNC, 03101 + +# Add some other naming to make my life easier +.equ STDIN, 0 +.equ STDOUT, 1 +.equ STDERR, 2 + +.equ END_OF_FILE, 0 + +.equ NUMBER_ARGUMENTS, 2 + +################################################################ + +.section .bss + +.equ BUFFER_SIZE, 500 +.lcomm BUFFER_DATA, BUFFER_SIZE + +################################################################ + +.section .text + +# STACK POSITIONS + +.equ ST_SIZE_RESERVE, 16 +.equ ST_FD_IN, -8 +.equ ST_FD_OUT, -16 +.equ ST_ARGC, 0 # Number of arguments +.equ ST_ARGV_0, 8 # Program's name +.equ ST_ARGV_1, 16 # Input file name +.equ ST_ARGV_2, 24 # Output file name + +.globl _start +.global convert_to_upper # Declaration only + +### START OF PROGRAM ### +_start: + + # Save stack pointer + movq %rsp, %rbp + + # Alloc space for FDs on the stack + subq $ST_SIZE_RESERVE, %rsp + +# Labels are here just to make my life easier in splitting the sections +# I won't be jumping around... + +# int open(const char *pathname, int flags, mode_t mode) +# Argument's order: %rdi, %rsi, %rdx + +open_files: +open_fd_in: + movq $SYS_OPEN, %rax # Setup syscall number + movq ST_ARGV_1(%rbp), %rdi # input filename into %rdi + movq $O_RDONLY, %rsi # Open in O_RDONLY + movq $0666, %rdx # regular posix perms + syscall # Invoke kernel to call sys_open() + +store_fd_in: + movq %rax, ST_FD_IN(%rbp) # Save file's FD + +open_fd_out: + movq $SYS_OPEN, %rax # Setup syscall number + movq ST_ARGV_2(%rbp), %rdi # Output file name location to %ebx + movq $O_CREAT_WRONLY_TRUNC, %rsi# Setup writing flags + movq $0666, %rdx # POSIX mode + syscall # Invoke kernel (sys_open()) + +store_fd_out: + movq %rax, ST_FD_OUT(%rbp) # Save output FD in the stack + + +################################################################ + +# ssize_t read(int fd, void *buf, size_t count); +# ssize_t write(int fd, const void *buf, size_t count); + +read_loop_begin: + movq $SYS_READ, %rax + movq ST_FD_IN(%rbp), %rdi # Read from this FD + movq $BUFFER_DATA, %rsi # Copy buffer's address to %rsi, so + # read() knows where to put data read + + movq $BUFFER_SIZE, %rdx # Set buffer size for read() + syscall # Invoke kernel + + # Number of bytes read should be in %eax + + # Leave loop if we are at EOF + cmpq $END_OF_FILE, %rax + jle end_loop + +continue_read_loop: + # Call convert function for the current buffer + pushq $BUFFER_DATA # Buffer location - 2nd argument + pushq %rax # Buffer size - 1st argument + # (returned from read() syscall) + + call convert_to_upper + popq %rax # get size back + addq $8, %rsp # Cleanup stack used for buffer_data location + +write_file: + movq %rax, %rdx # Use number of bytes read to write to + # output file + movq $SYS_WRITE, %rax + movq ST_FD_OUT(%rbp), %rdi # Write to this FD + movq $BUFFER_DATA, %rsi # This buffer + syscall # Invoke kernel + + jmp read_loop_begin # Keep reading the file + +end_loop: + movq $SYS_CLOSE, %rax + movq ST_FD_OUT(%rbp), %rdi + syscall + + movq $SYS_CLOSE, %rax + movq ST_FD_IN(%rbp), %rdi + syscall + + movq $SYS_EXIT, %rax + movq $0, %rdi + syscall + + +# convert_to_upper: +# +# Convert all ascii characters in $BUFFER +# to uppercase +# +# - 1st argument: Buffer size +# - 2nd argument: Buffer address +# +# REMEMBER: Arguments must be pushed in the reverse order as they are documented +# +# - %eax - beginning of buffer +# - %rdi - buffer length +# - %rsi - current buffer offset +# - %cl - byte being examined (lower byte of %rcx) + +## CONSTANTS +.equ LOWERCASE_A, 'a' # lower bundary +.equ LOWERCASE_Z, 'z' # upper boundary + +# CONVERSION +.equ UPPER_CONVERSION, 'A' - 'a' + +## STACK STUFF +.equ ST_BUFFER_LEN, 16 # Buffer length +.equ ST_BUFFER, 24 # Actual Buffer + + +.type convert_to_upper, @function + +convert_to_upper: + pushq %rbp # Setup function's stack frame. Save current %ebp + movq %rsp, %rbp # And set it to current stack pointer + + movq ST_BUFFER(%rbp), %rax + movq ST_BUFFER_LEN(%rbp), %rdi + movq $0, %rsi + + # If a zero length buffer was given, just leave + cmpq $0, %rax + je end_convert_loop + +convert_loop: + movb (%rax, %rsi, 1), %cl # Get current byte + + # Check if current byte is already in low case + cmpb $LOWERCASE_A, %cl + jl next_byte + cmpb $LOWERCASE_Z, %cl + jg next_byte + + # Convert if we are still here + addb $UPPER_CONVERSION, %cl + movb %cl, (%rax, %rsi, 1) # Replace old value with the new one + +next_byte: + incq %rsi + cmpq %rsi, %rdi # Continue conversion unless we reached + jne convert_loop # the end of the buffer + +end_convert_loop: + # no return value, just restore stack pointer + # and base pointer and return. + movq %rbp, %rsp + popq %rbp + ret + -- cgit v1.2.3