summaryrefslogtreecommitdiff
path: root/PGU/CHAP5
diff options
context:
space:
mode:
authorCarlos Maiolino <[email protected]>2025-07-10 22:55:07 +0200
committerCarlos Maiolino <[email protected]>2025-07-10 22:56:55 +0200
commitd98f46ce647846b0aa30b2e16a30fd4e152a1bf5 (patch)
tree267474fcc77cf20b428f6f4c7f768ca09f4cfe0e /PGU/CHAP5
parent869e68986aa8f69af6e7842260a68d1e5c6f796f (diff)
Add new code
Signed-off-by: Carlos Maiolino <[email protected]>
Diffstat (limited to 'PGU/CHAP5')
-rw-r--r--PGU/CHAP5/argtest.s20
-rw-r--r--PGU/CHAP5/toupper.s206
-rw-r--r--PGU/CHAP5/toupper.up206
3 files changed, 432 insertions, 0 deletions
diff --git a/PGU/CHAP5/argtest.s b/PGU/CHAP5/argtest.s
new file mode 100644
index 0000000..aded606
--- /dev/null
+++ b/PGU/CHAP5/argtest.s
@@ -0,0 +1,20 @@
+.section .data
+
+.section .text
+
+.globl _start
+
+_start:
+ movq %rsp, %rbp
+ movq (%rbp), %r12
+ movq 16(%rbp), %r13
+
+ movq $2, %rax #SYS_OPEN
+ movq %r13, %rdi
+ movq $0, %rsi
+ syscall
+
+ movq %r12, %rdi
+ movq $60, %rax
+ syscall
+
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
+
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
+