summaryrefslogtreecommitdiff
path: root/PGU/CHAP5/toupper.up
diff options
context:
space:
mode:
Diffstat (limited to 'PGU/CHAP5/toupper.up')
-rw-r--r--PGU/CHAP5/toupper.up206
1 files changed, 206 insertions, 0 deletions
diff --git a/PGU/CHAP5/toupper.up b/PGU/CHAP5/toupper.up
new file mode 100644
index 0000000..d4c2367
--- /dev/null
+++ b/PGU/CHAP5/toupper.up
@@ -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
+