summaryrefslogtreecommitdiff
path: root/PGU/CHAP5/toupper.s
diff options
context:
space:
mode:
Diffstat (limited to 'PGU/CHAP5/toupper.s')
-rw-r--r--PGU/CHAP5/toupper.s206
1 files changed, 206 insertions, 0 deletions
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
+