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.up | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 PGU/CHAP5/toupper.up (limited to 'PGU/CHAP5/toupper.up') 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 + -- cgit v1.2.3