summaryrefslogtreecommitdiff
path: root/PGU
diff options
context:
space:
mode:
Diffstat (limited to 'PGU')
-rw-r--r--PGU/CHAP10/convprog.s35
-rw-r--r--PGU/CHAP10/count-chars.s47
-rw-r--r--PGU/CHAP10/int2str.s86
-rw-r--r--PGU/CHAP10/linux.s16
-rw-r--r--PGU/CHAP10/write-newline.s29
-rw-r--r--PGU/CHAP3/exit.s23
-rw-r--r--PGU/CHAP3/max_value.s65
-rw-r--r--PGU/CHAP4/factorial.s67
-rw-r--r--PGU/CHAP4/power.s94
-rw-r--r--PGU/CHAP5/argtest.s20
-rw-r--r--PGU/CHAP5/toupper.s206
-rw-r--r--PGU/CHAP5/toupper.up206
-rw-r--r--PGU/CHAP6_7/count-chars.s47
-rw-r--r--PGU/CHAP6_7/error.s46
-rw-r--r--PGU/CHAP6_7/linux.s16
-rw-r--r--PGU/CHAP6_7/modify-records.s86
-rw-r--r--PGU/CHAP6_7/read-records.s74
-rw-r--r--PGU/CHAP6_7/read_write.s62
-rw-r--r--PGU/CHAP6_7/record-def.s7
-rw-r--r--PGU/CHAP6_7/write-newline.s29
-rw-r--r--PGU/CHAP6_7/write_records.s135
-rw-r--r--PGU/CHAP8/helloworld-lib.s20
-rw-r--r--PGU/CHAP8/helloworld-nolib.s25
-rw-r--r--PGU/CHAP8/linux.s16
-rw-r--r--PGU/CHAP8/printcall.s34
-rw-r--r--PGU/CHAP9/count-chars.s47
-rw-r--r--PGU/CHAP9/error.s46
-rw-r--r--PGU/CHAP9/linux.s16
-rw-r--r--PGU/CHAP9/memalloc.s303
-rw-r--r--PGU/CHAP9/read-records.s86
-rw-r--r--PGU/CHAP9/read_write.s62
-rw-r--r--PGU/CHAP9/record-def.s7
-rw-r--r--PGU/CHAP9/write-newline.s29
-rw-r--r--PGU/OLD/asm/exit.s17
-rw-r--r--PGU/OLD/asm/max.c27
-rw-r--r--PGU/OLD/asm/max.s39
-rw-r--r--PGU/OLD/asm/maximumbin0 -> 1120 bytes
-rw-r--r--PGU/OLD/asm/maximum.s14
-rw-r--r--PGU/OLD/chapter3/exitbin0 -> 704 bytes
-rw-r--r--PGU/OLD/chapter3/exit.s70
-rw-r--r--PGU/OLD/chapter3/max.s42
-rw-r--r--PGU/OLD/chapter3/min.s52
-rw-r--r--PGU/OLD/chapter4/call_power.c12
-rw-r--r--PGU/OLD/chapter4/factorial.s73
-rw-r--r--PGU/OLD/chapter4/libpower.s48
-rw-r--r--PGU/OLD/chapter4/power.s90
46 files changed, 2571 insertions, 0 deletions
diff --git a/PGU/CHAP10/convprog.s b/PGU/CHAP10/convprog.s
new file mode 100644
index 0000000..49ac6fb
--- /dev/null
+++ b/PGU/CHAP10/convprog.s
@@ -0,0 +1,35 @@
+.include "linux.s"
+
+.section .data
+
+tmp_buffer:
+ .ascii "\0\0\0\0\0\0\0\0\0\0\0"
+
+.section .text
+
+.globl _start
+
+_start:
+ movq %rsp, %rbp
+
+ pushq $tmp_buffer
+ pushq $824
+ call integer2string
+ addq $16, %rsp
+
+ pushq $tmp_buffer
+ call count_chars
+ addq $8, %rsp
+
+ movq %rax, %rdx
+ movq $STDOUT, %rdi
+ movq $tmp_buffer, %rsi
+ movq $SYS_WRITE, %rax
+ syscall
+
+ pushq $STDOUT
+ call write_newline
+
+ movq $SYS_EXIT, %rax
+ movq $0, %rdi
+ syscall
diff --git a/PGU/CHAP10/count-chars.s b/PGU/CHAP10/count-chars.s
new file mode 100644
index 0000000..7e12791
--- /dev/null
+++ b/PGU/CHAP10/count-chars.s
@@ -0,0 +1,47 @@
+# Count the characters in a string (until a null byte is reached)
+# It's supposed to behave similarly with strlen()
+#
+# Returns the count in %rax
+#
+# - %rcx: Char count
+# - %rdx: current Char address
+# - %al: current char
+#
+
+.type count_chars, @function
+.globl count_chars
+
+# We receive the string addr in the stack.
+# Remember %rsp + 8 contains the return value
+.equ ST_STRING_ADDRESS, 16
+
+count_chars:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ #initialize counter
+ movq $0, %rcx
+
+ # Start address of string:
+ movq ST_STRING_ADDRESS(%rbp), %rdx
+
+count_loop_begin:
+
+ # Grab char
+ movb (%rdx), %al
+
+ cmpb $0, %al
+ je count_loop_end
+
+ # We are not done yet...
+ incq %rcx
+ incq %rdx
+ jmp count_loop_begin
+
+count_loop_end:
+
+ movq %rcx, %rax
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/CHAP10/int2str.s b/PGU/CHAP10/int2str.s
new file mode 100644
index 0000000..6ea5178
--- /dev/null
+++ b/PGU/CHAP10/int2str.s
@@ -0,0 +1,86 @@
+# integer2string
+#
+# Convert an int number to a decima string for display
+#
+# Receives a buffer large enough to hold the largest possible numberr
+# and an integer to convert
+#
+# %rcx hold the count of characters processed
+# %rax holds the current value
+# %rdi hold the base (10)
+
+.equ ST_VALUE, 16
+.equ ST_BUFFER, 24
+
+.globl integer2string
+.type integer2string, @function
+
+integer2string:
+
+ # Default function setup
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq $0, %rcx # Init char count
+ movq ST_VALUE(%rbp), %rax # Retrieve value from stack
+
+ # The divisor must be in a register or memory location
+ movq $10, %rdi
+
+ conversion_loop:
+ # Division is actually performed on the combined
+ # %rdx:%rax register, so first, clear out %rdx
+ movq $0, %rdx
+
+ # Divide %rdx:%rax (which are implied) by 10
+ # Store the quotient in %rax and the remainder in
+ # %rdx (both which are implied)
+ divq %rdi
+
+ # Quotient is in the right place. %rdx has the remainder
+ # which now needs to be converted into a number. So, %rdx has a
+ # number that is 0 through 9. We'll use it as an 'index' on the
+ # ASCII table starting from char '0'.
+ addq $'0', %rdx # Get our number's index from ASCII
+ # table, starting from '0'.
+
+ # Push this value into the stack. When we are done, we can just
+ # pop them off one-by-one, and they will be in the right order.
+ # NOTE: We are pushing the whole register, but we only need the
+ # byte in %dl (The last byte of the %rdx register) for the
+ # character.
+ pushq %rdx
+
+ incq %rcx # Increment digit count
+
+ cmpq $0, %rax # Have we reached the end of the calculation?
+ je end_conversion_loop
+
+ # %rax has its new value
+ jmp conversion_loop
+
+ end_conversion_loop:
+ # The string is now on the stack, if we pop it off a char at a
+ # time, we can copy it into the buffer and we are done.
+
+ movq ST_BUFFER(%rbp), %rdx # Move buffer address to %rdx
+
+ copy_reversing_loop:
+ popq %rax
+ movb %al, (%rdx)
+ decq %rcx # Once we reach 0 we are finished
+ incq %rdx # Point to the next byte
+
+ cmpq $0, %rcx # Check if we are finished
+ je end_copy_reversing_loop
+
+ jmp copy_reversing_loop
+
+ end_copy_reversing_loop:
+ movb $0, (%rdx)
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+# end of integer2string
diff --git a/PGU/CHAP10/linux.s b/PGU/CHAP10/linux.s
new file mode 100644
index 0000000..9ab8243
--- /dev/null
+++ b/PGU/CHAP10/linux.s
@@ -0,0 +1,16 @@
+# Syscall numbers (x86_64)
+
+.equ SYS_EXIT, 60
+.equ SYS_READ, 0
+.equ SYS_WRITE, 1
+.equ SYS_OPEN, 2
+.equ SYS_CLOSE, 3
+.equ SYS_BRK, 12
+
+# Default File Descriptors
+.equ STDIN, 0
+.equ STDOUT, 1
+.equ STDERR, 2
+
+# Common Status Codes
+.equ END_OF_FILE, 0
diff --git a/PGU/CHAP10/write-newline.s b/PGU/CHAP10/write-newline.s
new file mode 100644
index 0000000..e916379
--- /dev/null
+++ b/PGU/CHAP10/write-newline.s
@@ -0,0 +1,29 @@
+# Just write a newline (\n) to STDOUT
+
+.include "linux.s"
+.type write_newline, @function
+.globl write_newline
+
+.section .data
+
+newline:
+ .ascii "\n"
+
+.section .text
+ .equ ST_FILEDES, 16
+
+write_newline:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq $SYS_WRITE, %rax
+ movq ST_FILEDES(%rbp), %rdi
+ movq $newline, %rsi
+ movq $1, %rdx
+ syscall
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+
diff --git a/PGU/CHAP3/exit.s b/PGU/CHAP3/exit.s
new file mode 100644
index 0000000..df2addb
--- /dev/null
+++ b/PGU/CHAP3/exit.s
@@ -0,0 +1,23 @@
+# Program does not but exit() call with a status code
+# returned to kernel
+
+# No inputs or outputs
+
+# Variables
+#
+# %rax - holds syscall number
+# %rdi - holds return status
+
+.section .data
+#No data
+
+.section .text
+.globl _start
+
+_start:
+movq $60, %rax # %rax used to hold syscall numbers
+ # 60 is exit() syscall
+
+movq $245, %rdi # Exit status (BYTE MAX)
+
+syscall
diff --git a/PGU/CHAP3/max_value.s b/PGU/CHAP3/max_value.s
new file mode 100644
index 0000000..7025b05
--- /dev/null
+++ b/PGU/CHAP3/max_value.s
@@ -0,0 +1,65 @@
+# Find the maximum value inside a static list
+
+# Variables used:
+#
+# - %r11 - Holds index of the data item being examined
+# - %rdi - Largest data item found so far
+# - %rax - Current data item
+#
+#
+# Constant memory locations:
+#
+# data_items - contains the item data. (Marks the beginning actualy)
+# So far, 0 is used as terminator
+#
+# This program is written for x86_64 processors, it won't assemble in x86
+
+.section .data # Specify data section
+
+
+# Array of data items. This use 8bytes (quad-word) for each location
+data_items:
+.quad 133,55,50,12,25,77,30,93,222,55,62,250,66,34,69,0
+
+
+.section .text
+
+# Mark program's starting point so Linux can 'see' it
+.globl _start
+
+_start:
+movq $0, %r11 # Move 0 into %rdi to indicate
+ # the start of the index
+
+movq data_items(,%r11,8), %rax # Load the first data item (8bytes long)
+ # This actually uses indexed access
+ # mode, where %rdi is the 'offset' into
+ # the data_items array, and 8 is the
+ # multiplier.
+
+movq %rax, %rbx # This is the first item, so, %rax is
+ # current the biggest anyway
+
+
+# Loop over all items
+start_loop:
+ cmpq $0, %rax # compare current item with the
+ je loop_exit # terminator 0, and jump to exit
+ # if it is equal.
+
+ incq %r11 # Increment index so we can grab next
+ # item
+
+ movq data_items(,%r11,8), %rax # Grab next item once we incremented the
+ # index above
+
+ cmpq %rbx, %rax # If our current item in %rax is smaller
+ jle start_loop # we ignore it and move back to the loop
+
+ movq %rax, %rdi # Otherwise we store it as our new largest
+ jmp start_loop # item and jump back to the loop unconditionally
+
+loop_exit:
+ movq $60, %rax # Call exit() syscall, our argument is
+ # already in %rdi, just setup syscall
+ syscall # number and call kernel
diff --git a/PGU/CHAP4/factorial.s b/PGU/CHAP4/factorial.s
new file mode 100644
index 0000000..d4907b7
--- /dev/null
+++ b/PGU/CHAP4/factorial.s
@@ -0,0 +1,67 @@
+# Recursion example - calculates the factorial of a number
+
+# Everything goes in the stack, no data section needed
+.section .data
+
+.section .text
+
+.globl _start
+
+# This is pointless unless we are exporting this function to other programs or
+# files. It's just here for completeness.
+.global factorial
+
+_start:
+ pushq $4 # Push argument
+ call factorial # call command pushes the next instruction's address on
+ # the stack, when we return to it, it will pop the
+ # address off of the stack and point the Instruction
+ # pointer to it
+
+ addq $8, %rsp # Cleanup stack - Remove the argument from it
+ # Remember by cleanup, we just move the stackpointer
+ # back a word (8 bytes in x86_64) times the number of
+ # arguments pushed in the stack.
+
+ movq %rax, %rdi # Move result into exit() argument register %rdi
+ # Return values are always stored in %rax...
+
+ movq $60, %rax # Setup %rax to exit() syscall number
+ syscall # Invoke kernel's syscall
+
+
+# Tell linker this is a function
+# Export factorial as a function
+.type factorial, @function
+
+factorial:
+ # Create the stack frame for this function...
+ pushq %rbp # Save %rbp in the stack
+ movq %rsp, %rbp # And current stack pointer in %rbp
+
+ movq 16(%rbp), %rax # Retrieve argument from stack, remember, we're
+ # dealing with quad words, %rbp is at the
+ # beginning of the function's stack frame,
+ # 8(%rbp) is the function's return address setup
+ # by call command and
+ # 16(%rbp) is our argument pushed in the stack
+ # by the function's caller
+
+ cmpq $1, %rax # If we are at 1, nothing to be done...
+ je end_factorial
+
+ decq %rax # Otherwise we decrease our current operand
+ pushq %rax # and send it again to factorial function
+ call factorial # here...
+
+ movq 16(%rbp), %r8 # Retrieve our current argument again
+ imulq %r8, %rax # and multiply it by the result of the factorial
+ # below (num factorial = num * factorial of
+ # previous num, ex. 4! == 4 * 3!)
+
+end_factorial:
+
+ ## Clean up function's stack frame ##
+ movq %rbp, %rsp # We are done with this factorial, restore
+ popq %rbp # %rsp and %rbp and
+ ret # return to the caller
diff --git a/PGU/CHAP4/power.s b/PGU/CHAP4/power.s
new file mode 100644
index 0000000..124586e
--- /dev/null
+++ b/PGU/CHAP4/power.s
@@ -0,0 +1,94 @@
+# Power Program
+#
+# Computes the value of a number raised to a power
+# using functions.
+#
+
+# Everything in the main program is stored in registers
+# no need for data section
+.section .data
+
+.section .text
+
+.globl _start
+
+_start:
+
+ pushq $3 # Second argument (power)
+ pushq $2 # First argument (base)
+ call power # Call the function power
+
+ # Cleanup stack removing the arguments from it
+ addq $16, %rsp
+
+ # Save the answer in the stack before calling power again
+ push %rax
+
+ pushq $2 # Second argument (Power)
+ pushq $5 # First argument (Base)
+ call power
+
+ addq $16, %rsp # Cleanup stack
+
+ # Second answer is already in %rax, get the first
+ # back from stack to %rdi
+ popq %rdi
+
+ # Just add them
+ addq %rax, %rdi
+
+ #Sum is already in %rdi, just call exit() with %rdi as argument
+ movq $60, %rax
+ syscall
+
+
+
+##################
+# Power Function #
+##################
+
+# - First Arg - Base power
+# - Second Arg - The power to raise it to
+#
+# NOTE: So far, power must be 1 or greater
+#
+# Variables
+#
+# - %rbx - holds the base number
+# - %rcx - holds the power (also acts as a counter)
+# - -8(%rbp) holds the current result
+
+.type power, @function
+
+power:
+ pushq %rbp # Save old Base Pointer
+ movq %rsp, %rbp # make stack pointer the base pointer
+ subq $8, %rsp # Add space in stack for local storage
+
+ movq 16(%rbp), %r8 # Retrieve Base number from stack to %rbx
+ movq 24(%rbp), %r9 # Retrieve second argument from stack to %rcx
+
+ movq %r8, -8(%rbp) # Store current result (the operand by itself)
+
+power_loop_start:
+ cmpq $1, %r9 # If power is 1, we are done
+ je end_power
+
+ movq -8(%rbp), %rax # Move current into %rax
+ imulq %r8, %rax # Multiply current result by base number
+
+ movq %rax, -8(%rbp) # Save current result
+
+ decq %r9 # Decrease the power (using as a counter)
+ jmp power_loop_start
+
+end_power:
+ movq -8(%rbp), %rax # Retrieve end result into %rax
+ # Return value goes into %rax
+ movq %rbp, %rsp # Restore stack pointer
+ popq %rbp # Restore base pointer
+ ret
+
+
+
+
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
+
diff --git a/PGU/CHAP6_7/count-chars.s b/PGU/CHAP6_7/count-chars.s
new file mode 100644
index 0000000..7e12791
--- /dev/null
+++ b/PGU/CHAP6_7/count-chars.s
@@ -0,0 +1,47 @@
+# Count the characters in a string (until a null byte is reached)
+# It's supposed to behave similarly with strlen()
+#
+# Returns the count in %rax
+#
+# - %rcx: Char count
+# - %rdx: current Char address
+# - %al: current char
+#
+
+.type count_chars, @function
+.globl count_chars
+
+# We receive the string addr in the stack.
+# Remember %rsp + 8 contains the return value
+.equ ST_STRING_ADDRESS, 16
+
+count_chars:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ #initialize counter
+ movq $0, %rcx
+
+ # Start address of string:
+ movq ST_STRING_ADDRESS(%rbp), %rdx
+
+count_loop_begin:
+
+ # Grab char
+ movb (%rdx), %al
+
+ cmpb $0, %al
+ je count_loop_end
+
+ # We are not done yet...
+ incq %rcx
+ incq %rdx
+ jmp count_loop_begin
+
+count_loop_end:
+
+ movq %rcx, %rax
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/CHAP6_7/error.s b/PGU/CHAP6_7/error.s
new file mode 100644
index 0000000..6e933ed
--- /dev/null
+++ b/PGU/CHAP6_7/error.s
@@ -0,0 +1,46 @@
+# Error function
+#
+# Print error messages and exit program.
+
+.include "linux.s"
+.equ ST_ERROR_CODE, 16
+.equ ST_ERROR_MSG, 24
+
+.globl error_exit
+.type error_exit, @function
+
+error_exit:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # Write error Code
+ movq ST_ERROR_CODE(%rbp), %rcx
+ pushq %rcx
+ call count_chars
+ popq %rcx
+
+ movq %rax, %rdx
+ movq %rcx, %rsi
+ movq $STDERR, %rdi
+ movq $SYS_WRITE, %rax
+ syscall
+
+ # Write error message
+ movq ST_ERROR_MSG(%rbp), %rcx
+ pushq %rcx
+ call count_chars
+ popq %rcx
+
+ movq %rax, %rdx # How many bytes to write
+ movq %rcx, %rsi # Buffer to write from
+ movq $STDERR, %rdi # FD to write to
+ movq $SYS_WRITE, %rax # self explanatory
+ syscall
+
+ pushq $STDERR
+ call write_newline
+
+ # Exit program
+ movq $SYS_EXIT, %rax
+ movq $1, %rdi
+ syscall
diff --git a/PGU/CHAP6_7/linux.s b/PGU/CHAP6_7/linux.s
new file mode 100644
index 0000000..9ab8243
--- /dev/null
+++ b/PGU/CHAP6_7/linux.s
@@ -0,0 +1,16 @@
+# Syscall numbers (x86_64)
+
+.equ SYS_EXIT, 60
+.equ SYS_READ, 0
+.equ SYS_WRITE, 1
+.equ SYS_OPEN, 2
+.equ SYS_CLOSE, 3
+.equ SYS_BRK, 12
+
+# Default File Descriptors
+.equ STDIN, 0
+.equ STDOUT, 1
+.equ STDERR, 2
+
+# Common Status Codes
+.equ END_OF_FILE, 0
diff --git a/PGU/CHAP6_7/modify-records.s b/PGU/CHAP6_7/modify-records.s
new file mode 100644
index 0000000..4cf2d92
--- /dev/null
+++ b/PGU/CHAP6_7/modify-records.s
@@ -0,0 +1,86 @@
+# Modify records in a file and write them to the output file
+.include "linux.s"
+.include "record-def.s"
+
+.section .data
+ input_filename:
+ .ascii "test.dat\0"
+ output_filename:
+ .ascii "modified.dat\0"
+
+.section .bss
+ .lcomm record_buffer, RECORD_SIZE
+
+
+.section .text
+.globl _start
+
+_start:
+ # Stack local vars
+ .equ ST_INPUT_DESCRIPTOR, -8
+ .equ ST_OUTPUT_DESCRIPTOR, -16
+
+ # Copy stack pointer and make room for local variables
+ movq %rsp, %rbp
+ subq $16, %rsp
+
+ # Open file for reading
+ movq $SYS_OPEN, %rax
+ movq $input_filename, %rdi
+ movq $0, %rsi
+ movq $0666, %rdx
+ syscall
+
+ cmpq $0, %rax
+ jl continue_processing
+
+ # We've got an error...
+continue_processing:
+ movq %rax, ST_INPUT_DESCRIPTOR(%rbp)
+
+ .section .data
+ no_open_file_code:
+ .ascii "0001: \0"
+ no_open_file_msg:
+ .ascii "Can't open input file\0"
+ .section .text
+ pushq $no_open_file_msg
+ pushq $no_open_file_code
+ call error_exit
+
+ # Open file for writing
+ movq $SYS_OPEN, %rax
+ movq $output_filename, %rdi
+ movq $0101, %rsi
+ movq $0666, %rdx
+ syscall
+
+ movq %rax, ST_OUTPUT_DESCRIPTOR(%rbp)
+
+loop_begin:
+ pushq ST_INPUT_DESCRIPTOR(%rbp)
+ pushq $record_buffer
+ call read_record
+ addq $16, %rsp
+
+ # Return number of bytes read. If it's not the same as
+ # $RECORD_SIZE, then we are either at EOF or we hit an error.
+ cmpq $RECORD_SIZE, %rax
+ jne loop_end
+
+ # Increment age...
+ incq record_buffer + RECORD_AGE
+
+ # Write record to the output file
+ pushq ST_OUTPUT_DESCRIPTOR(%rbp)
+ pushq $record_buffer
+ call write_record
+ addq $16, %rsp
+
+ jmp loop_begin
+
+loop_end:
+
+ movq $SYS_EXIT, %rax
+ movq $0, %rbx
+ syscall
diff --git a/PGU/CHAP6_7/read-records.s b/PGU/CHAP6_7/read-records.s
new file mode 100644
index 0000000..89b1e91
--- /dev/null
+++ b/PGU/CHAP6_7/read-records.s
@@ -0,0 +1,74 @@
+# Read records previously written in file.dat, by write-records software
+
+.include "linux.s"
+.include "record-def.s"
+
+.section .data
+ filename:
+ .ascii "test.dat\0"
+
+.section .bss
+ .lcomm record_buffer, RECORD_SIZE
+
+.section .text
+
+.globl _start
+
+_start:
+ # Stack locations for INPUT and OUTPUT FDs
+ .equ ST_INPUT_DESCRIPTOR, -8
+ .equ ST_OUTPUT_DESCRIPTOR, -16
+
+ movq %rsp, %rbp
+ subq $16, %rsp # Save space in the stack for FDs
+
+ # Open data file
+ movq $SYS_OPEN, %rax
+ movq $filename, %rdi
+ movq $0, %rsi # Open for read only
+ movq $0666, %rdx
+ syscall
+
+ # Save FD
+ movq %rax, ST_INPUT_DESCRIPTOR(%rbp)
+
+ # Yes, STDOUT is always 1, but if I want to change the output location
+ # later, I don't need to change everywhere...
+ movq $STDOUT, ST_OUTPUT_DESCRIPTOR(%rbp)
+
+record_read_loop:
+ pushq ST_INPUT_DESCRIPTOR(%rbp)
+ pushq $record_buffer
+ call read_record
+ addq $16, %rsp # Cleanup stack
+
+ # All records are RECORD_SIZE size, if we didn't get this amount of
+ # bytes from read function, we either are at EOF or we hit an error.
+ cmpq $RECORD_SIZE, %rax
+ jne finished_reading
+
+ # We are ok, so print the first name in the record
+ pushq $RECORD_FIRSTNAME + record_buffer # Location of firstname
+ # record in the buffer
+ # we just read
+ call count_chars
+ addq $8, %rsp # Cleanup stack
+
+ # Write name to OUTPUT
+ movq %rax, %rdx # Returned record size, used as argument to
+ # write()
+ movq $RECORD_FIRSTNAME + record_buffer, %rsi
+ movq ST_OUTPUT_DESCRIPTOR(%rbp), %rdi
+ movq $SYS_WRITE, %rax
+ syscall
+
+ pushq ST_OUTPUT_DESCRIPTOR(%rbp)
+ call write_newline
+ addq $8, %rsp
+
+ jmp record_read_loop
+
+finished_reading:
+ movq $SYS_EXIT, %rax
+ movq $0, %rdi
+ syscall
diff --git a/PGU/CHAP6_7/read_write.s b/PGU/CHAP6_7/read_write.s
new file mode 100644
index 0000000..d574013
--- /dev/null
+++ b/PGU/CHAP6_7/read_write.s
@@ -0,0 +1,62 @@
+.include "record-def.s"
+.include "linux.s"
+
+# Read function
+# Reads a record from the file descriptor
+# and writes it into the buffer passed
+
+# STACK VARS - Used for both read and write functions. They don't share the
+# location, but the arguments are passed in the same position
+# for both, so, no need to create different location vars.
+
+.equ ST_BUFFER, 16 # Ret address is at %rsp+8
+.equ ST_FILEDES, 24
+
+.section .text
+
+.globl read_record
+.type read_record, @function
+
+read_record:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # READ A RECORD
+ pushq %rdi
+ movq ST_FILEDES(%rbp), %rdi
+ movq ST_BUFFER(%rbp), %rsi
+ movq $RECORD_SIZE, %rdx
+ movq $SYS_READ, %rax
+ syscall
+
+ # NOTE: %rax has the return value, which we will give back
+ # to our caller
+
+ popq %rdi
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+.globl write_record
+.type write_record, @function
+
+write_record:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # WRITE A RECORD
+ pushq %rdi
+ movq ST_FILEDES(%rbp), %rdi
+ movq ST_BUFFER(%rbp), %rsi
+ movq $RECORD_SIZE, %rdx
+ movq $SYS_WRITE, %rax
+ syscall
+
+ # NOTE: %rax has the return value, which we will give back
+ # to our caller
+ popq %rdi
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/CHAP6_7/record-def.s b/PGU/CHAP6_7/record-def.s
new file mode 100644
index 0000000..9e5274d
--- /dev/null
+++ b/PGU/CHAP6_7/record-def.s
@@ -0,0 +1,7 @@
+# Define offsets within a record
+
+.equ RECORD_FIRSTNAME, 0
+.equ RECORD_LASTNAME, 40
+.equ RECORD_ADDRESS, 80
+.equ RECORD_AGE, 320 # Use 8 bytes for age, because it's
+.equ RECORD_SIZE, 328 # simpler to deal with whole words
diff --git a/PGU/CHAP6_7/write-newline.s b/PGU/CHAP6_7/write-newline.s
new file mode 100644
index 0000000..e916379
--- /dev/null
+++ b/PGU/CHAP6_7/write-newline.s
@@ -0,0 +1,29 @@
+# Just write a newline (\n) to STDOUT
+
+.include "linux.s"
+.type write_newline, @function
+.globl write_newline
+
+.section .data
+
+newline:
+ .ascii "\n"
+
+.section .text
+ .equ ST_FILEDES, 16
+
+write_newline:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq $SYS_WRITE, %rax
+ movq ST_FILEDES(%rbp), %rdi
+ movq $newline, %rsi
+ movq $1, %rdx
+ syscall
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+
diff --git a/PGU/CHAP6_7/write_records.s b/PGU/CHAP6_7/write_records.s
new file mode 100644
index 0000000..e52d7e0
--- /dev/null
+++ b/PGU/CHAP6_7/write_records.s
@@ -0,0 +1,135 @@
+.include "linux.s"
+.include "record-def.s"
+
+.section .data
+
+# Constant data of the records we want to write
+# Each data item is padded to the proper length
+# With null (i.e 0) bytes
+
+# .rept is used to pad each item. .rept tells the assembler to repeat the
+# section between .rept and .endr the number of times specified.
+# This is used in this program to add extra null chars at the end of each field
+# to fill the record up to the record size.
+
+# START OF RECORDS
+record1:
+ # First name
+ .ascii "Fredrick\0"
+ .rept 31 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Last name
+ .ascii "Bardlet\0"
+ .rept 31 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Address
+ .ascii "4242 S Prairie\nTulsa, OK 55555\0"
+ .rept 209 # Padding to 240 bytes
+ .byte 0
+ .endr
+
+ # Age
+ .long 45 # Field is 8 bytes long (1 word)
+
+record2:
+ # First name
+ .ascii "Marilyn\0"
+ .rept 32 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Last name
+ .ascii "Taylor\0"
+ .rept 33 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Address
+ .ascii "2224 S Johannan St\nChicago, IL 12345\0"
+ .rept 203 # Padding to 240 bytes
+ .byte 0
+ .endr
+
+ # Age
+ .long 29 # Field is 8 bytes long (1 word)
+
+record3:
+ # First name
+ .ascii "Derrick\0"
+ .rept 32 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Last name
+ .ascii "McIntire\0"
+ .rept 31 # Padding to 40 bytes
+ .byte 0
+ .endr
+
+ # Address
+ .ascii "500 W Oakland\nSan Diego, CA 54321\0"
+ .rept 206 # Padding to 240 bytes
+ .byte 0
+ .endr
+
+ # Age
+ .long 36 # Field is 8 bytes long (1 word)
+
+# END OF RECORDS
+
+
+.section .text
+# File we'll be writing to
+file_name:
+ .ascii "test.dat\0"
+
+.equ ST_FILE_DESCRIPTOR, -8
+
+.globl _start
+.global write_record
+
+_start:
+ movq %rsp, %rbp
+ subq $8, %rsp # Allocate space in stack for FD
+
+ # Open file
+ movq $SYS_OPEN, %rax
+ movq $file_name, %rdi
+ movq $0101, %rsi # Open for writing, create if it doesn't exist
+ movq $0666, %rdx
+ syscall
+
+ # Store FD:
+ movq %rax, ST_FILE_DESCRIPTOR(%rbp)
+
+ # Write first record
+ pushq ST_FILE_DESCRIPTOR(%rbp)
+ pushq $record1
+ call write_record
+ addq $16, %rsp #cleanup stack
+
+ # Write second record
+ pushq ST_FILE_DESCRIPTOR(%rbp)
+ pushq $record2
+ call write_record
+ addq $16, %rsp
+
+ # Write third record
+ pushq ST_FILE_DESCRIPTOR(%rbp)
+ pushq $record3
+ call write_record
+ addq $16, %rsp
+
+ # Close FD
+ movq $SYS_CLOSE, %rax
+ movq ST_FILE_DESCRIPTOR(%rbp), %rdi
+ syscall
+
+ # We are done, just exit
+ movq $SYS_EXIT, %rax
+ movq $0, %rdi
+ syscall
diff --git a/PGU/CHAP8/helloworld-lib.s b/PGU/CHAP8/helloworld-lib.s
new file mode 100644
index 0000000..6e04968
--- /dev/null
+++ b/PGU/CHAP8/helloworld-lib.s
@@ -0,0 +1,20 @@
+# Hello world using DSOs
+
+.section .data
+ helloworld:
+ .ascii "hello world\n\0"
+
+.section .text
+
+.globl _start
+
+_start:
+
+ # This differs from the book. In x86_64, arguments are passed through
+ # registers most of the time, in contrast with i386, where we can push
+ # them in the stack.
+ movq $helloworld, %rdi
+ call printf
+
+ movq $50, %rdi
+ call exit
diff --git a/PGU/CHAP8/helloworld-nolib.s b/PGU/CHAP8/helloworld-nolib.s
new file mode 100644
index 0000000..83d52ce
--- /dev/null
+++ b/PGU/CHAP8/helloworld-nolib.s
@@ -0,0 +1,25 @@
+# Write "hello world" and exit
+
+.include "linux.s"
+
+.section .data
+ helloworld:
+ .ascii "hello world\n"
+ helloworld_end:
+
+ .equ helloworld_len, helloworld_end - helloworld
+
+.section .text
+
+.globl _start
+
+_start:
+ movq $STDOUT, %rdi
+ movq $helloworld, %rsi
+ movq $helloworld_len, %rdx
+ movq $SYS_WRITE, %rax
+ syscall
+
+ movq $0, %rdi
+ movq $SYS_EXIT, %rax
+ syscall
diff --git a/PGU/CHAP8/linux.s b/PGU/CHAP8/linux.s
new file mode 100644
index 0000000..9ab8243
--- /dev/null
+++ b/PGU/CHAP8/linux.s
@@ -0,0 +1,16 @@
+# Syscall numbers (x86_64)
+
+.equ SYS_EXIT, 60
+.equ SYS_READ, 0
+.equ SYS_WRITE, 1
+.equ SYS_OPEN, 2
+.equ SYS_CLOSE, 3
+.equ SYS_BRK, 12
+
+# Default File Descriptors
+.equ STDIN, 0
+.equ STDOUT, 1
+.equ STDERR, 2
+
+# Common Status Codes
+.equ END_OF_FILE, 0
diff --git a/PGU/CHAP8/printcall.s b/PGU/CHAP8/printcall.s
new file mode 100644
index 0000000..2d50e73
--- /dev/null
+++ b/PGU/CHAP8/printcall.s
@@ -0,0 +1,34 @@
+# Just an example of calling printf() using ASM
+
+.section .data
+ firststring:
+ .ascii "Hello! %s is a %s who lives the number %d\n\0"
+ name:
+ .ascii "Maiolino\0"
+ personstring:
+ .ascii "person\0"
+
+ numberloved:
+ .long 123
+
+.section .text
+.globl _start
+
+ # Recall we are using x86_64 ABI here, so we pass arguments through
+ # registers instead of on the stack.
+
+_start:
+ movq $firststring, %rdi
+ movq $name, %rsi
+ movq $personstring, %rdx
+
+ # We don't use $numberloved here because $ sign means 'immediate'
+ # addressing. Here we want the 'CONTENT' pointed by label 'numberloved'
+ # so, we use 'direct' addressing, by ommiting the $ sign, so we get the
+ # information "pointed by" the label numberloved itself.
+ movq numberloved, %rcx
+ call printf
+
+ movq $0, %rdi
+ call exit
+
diff --git a/PGU/CHAP9/count-chars.s b/PGU/CHAP9/count-chars.s
new file mode 100644
index 0000000..7e12791
--- /dev/null
+++ b/PGU/CHAP9/count-chars.s
@@ -0,0 +1,47 @@
+# Count the characters in a string (until a null byte is reached)
+# It's supposed to behave similarly with strlen()
+#
+# Returns the count in %rax
+#
+# - %rcx: Char count
+# - %rdx: current Char address
+# - %al: current char
+#
+
+.type count_chars, @function
+.globl count_chars
+
+# We receive the string addr in the stack.
+# Remember %rsp + 8 contains the return value
+.equ ST_STRING_ADDRESS, 16
+
+count_chars:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ #initialize counter
+ movq $0, %rcx
+
+ # Start address of string:
+ movq ST_STRING_ADDRESS(%rbp), %rdx
+
+count_loop_begin:
+
+ # Grab char
+ movb (%rdx), %al
+
+ cmpb $0, %al
+ je count_loop_end
+
+ # We are not done yet...
+ incq %rcx
+ incq %rdx
+ jmp count_loop_begin
+
+count_loop_end:
+
+ movq %rcx, %rax
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/CHAP9/error.s b/PGU/CHAP9/error.s
new file mode 100644
index 0000000..6e933ed
--- /dev/null
+++ b/PGU/CHAP9/error.s
@@ -0,0 +1,46 @@
+# Error function
+#
+# Print error messages and exit program.
+
+.include "linux.s"
+.equ ST_ERROR_CODE, 16
+.equ ST_ERROR_MSG, 24
+
+.globl error_exit
+.type error_exit, @function
+
+error_exit:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # Write error Code
+ movq ST_ERROR_CODE(%rbp), %rcx
+ pushq %rcx
+ call count_chars
+ popq %rcx
+
+ movq %rax, %rdx
+ movq %rcx, %rsi
+ movq $STDERR, %rdi
+ movq $SYS_WRITE, %rax
+ syscall
+
+ # Write error message
+ movq ST_ERROR_MSG(%rbp), %rcx
+ pushq %rcx
+ call count_chars
+ popq %rcx
+
+ movq %rax, %rdx # How many bytes to write
+ movq %rcx, %rsi # Buffer to write from
+ movq $STDERR, %rdi # FD to write to
+ movq $SYS_WRITE, %rax # self explanatory
+ syscall
+
+ pushq $STDERR
+ call write_newline
+
+ # Exit program
+ movq $SYS_EXIT, %rax
+ movq $1, %rdi
+ syscall
diff --git a/PGU/CHAP9/linux.s b/PGU/CHAP9/linux.s
new file mode 100644
index 0000000..9ab8243
--- /dev/null
+++ b/PGU/CHAP9/linux.s
@@ -0,0 +1,16 @@
+# Syscall numbers (x86_64)
+
+.equ SYS_EXIT, 60
+.equ SYS_READ, 0
+.equ SYS_WRITE, 1
+.equ SYS_OPEN, 2
+.equ SYS_CLOSE, 3
+.equ SYS_BRK, 12
+
+# Default File Descriptors
+.equ STDIN, 0
+.equ STDOUT, 1
+.equ STDERR, 2
+
+# Common Status Codes
+.equ END_OF_FILE, 0
diff --git a/PGU/CHAP9/memalloc.s b/PGU/CHAP9/memalloc.s
new file mode 100644
index 0000000..6f354de
--- /dev/null
+++ b/PGU/CHAP9/memalloc.s
@@ -0,0 +1,303 @@
+
+# Alloc and Dealloc memory as requested
+#
+# Programs using these routines will ask
+# for a certain size of memory. We actually
+# use more than that size for metadata,
+# but we put it at the beginning, before the
+# pointer we hand back. We add a size field and
+# and AVAILABLE/UNAVAILABLE marker.
+#
+# The whole memory slot looks like this:
+#
+####################################################
+# Available marker | Size | Actual memory location #
+####################################################
+# ^-- returned pointer points
+# here
+#
+# The calling program won't see our metadata.
+
+### GLOBAL VARS ###
+.section .data
+
+############################### DEBUG INFO ################################
+
+# Originally, these labels heap_begin and current_break are .long long...
+# This implicitly means 4 bytes for each variable. This was causing the instructions
+# in allocate_init to overlap the variables when writing to them:
+
+# The following instructions were the problem:
+# movq %rax, current_break
+# allocated at 0x402011
+# movq %rax, heap_begin
+# allocated at 0x40200d
+#
+# Static allocation grows up in memory... But, when writing %rax to heap_begin,
+# due the variable sizes being 4bytes, the instruction was corrupting
+# current_break variable, causing the program to crash later in the allocation
+# loop, because the heap_begin allocation, consequently caused current_break to be
+# zero causing a NULL ptr dereference (or simply a SEGFAULT):
+
+# => 0x000000000040114e <+5>: mov 0x8(%rax),%rdx
+# Program received signal SIGSEGV, Segmentation fault.
+
+# allocate_init() disassemble:
+# 0x0000000000401105 <+0>: push %rbp
+# 0x0000000000401106 <+1>: mov %rsp,%rbp
+# 0x0000000000401109 <+4>: mov $0xc,%rax
+# 0x0000000000401110 <+11>: mov $0x0,%rdi
+# 0x0000000000401117 <+18>: syscall
+# 0x0000000000401119 <+20>: inc %rax
+# 0x000000000040111c <+23>: mov %rax,0x402011
+# 0x0000000000401124 <+31>: mov %rax,0x40200d
+#=> 0x000000000040112c <+39>: mov %rbp,%rsp
+# 0x000000000040112f <+42>: pop %rbp
+# 0x0000000000401130 <+43>: ret
+#
+# (gdb) info register rax
+# rax 0x403001 4206593
+# (gdb) p /x *0x40200d
+# $5 = 0x403001
+# (gdb) p /x *0x402011
+# $6 = 0x0 <-- Here, the address of current_break got zeroed after
+# heap_being has been changed
+
+############################# END OF DEBUG INFO #############################
+
+# Points to the beginning of the memory we are managing
+heap_begin:
+ .quad 0
+
+# Points to one locaiton past the memory we are managing
+current_break:
+ .quad 0
+
+### HEADER STRUCTURE INFORMATION ###
+
+# To make things simpler, we use one word for
+# each field in the header
+
+.equ HEADER_SIZE, 16 # size of space for memory region header
+.equ HDR_AVAIL_OFFSET, 0 # Location of the 'available' flag in the header
+.equ HDR_SIZE_OFFSET, 8 # Location of the size field in the header
+
+
+### CONSTANTS ###
+.equ UNAVAILABLE, 0
+.equ AVAILABLE, 1
+
+.equ SYS_BRK, 12 # syscall number for brk() syscall in x86_64
+
+
+.section .text
+
+### FUNCTIONS ###
+
+## allocate_init ##
+#
+# Call this function to initialize the functions by setting heap_begin and
+# current_break. No parameters and no return value
+
+.globl allocate_init
+.type allocate_init, @function
+
+allocate_init:
+ pushq %rbp # standard function stuff
+ movq %rsp, %rbp
+
+ # If brk() syscall is called with a 0 in %rdi, it returns the last valid
+ # usable address
+ movq $SYS_BRK, %rax
+ movq $0, %rdi
+ syscall
+
+ incq %rax # brk(0) returns the current break in %rax, we want the
+ # value after that
+
+ movq %rax, current_break # Store the current break (actually the address
+ # after that)
+
+ movq %rax, heap_begin # Our heap starts where the break is now. First
+ # address of uninitialized memory. This will
+ # cause the allocate function to get more memory
+ # from Linux the first time it is run.
+
+ movq %rbp, %rsp # Exit the function
+ popq %rbp
+ ret
+
+## END of allocate_init ##
+
+
+## allocate ##
+#
+# Grab a section of memory.
+# - Checks to see if there are any free blocks
+# - If not, asks Linux for more memory for the
+# heap through brk() syscall
+#
+# - Receives on parameter, the size of the memory block
+# we want to allocate
+#
+# - Returns the address of the allocated memory in %rax, or 0
+# if there is no memory available on the system
+#
+# ### Process
+#
+# %rcx - holds the size of requested memory (first/only parameter)
+# %rax - current memory region being examined
+# %rbx - Memory address past the end of the heap
+# %rdx - size of the current memory region
+#
+# We scan through each memory region starting with heap_begin. We look at the
+# size of each one and if it has been allocated. If it's big enough for the
+# requested size, and it's available, we grab that one. If we do not find a
+# region large enough, we ask Linux for more memory, which in case, moves the
+# current_break up.
+
+.globl allocate
+.type allocate, @function
+.equ ST_MEM_SIZE, 16 # Stack position of the memory size to allocate
+
+allocate:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq ST_MEM_SIZE(%rbp), %rcx # %rcx now holds the memory size we are
+ # looking for (first/only parameter)
+
+ movq heap_begin, %rax # %rax will hold the current search location
+ movq current_break, %rbx
+
+ alloc_loop_begin: # Scan memory regions
+
+ cmpq %rbx, %rax # heap needs more memory if these are
+ # equal. %rax will hold the end of the
+ # next memory region at each iteraction
+ # until it hits the current_break.
+
+ je move_break
+
+ # Retrieve the size of this mem slot
+ movq HDR_SIZE_OFFSET(%rax), %rdx
+
+ cmpq $UNAVAILABLE, HDR_AVAIL_OFFSET(%rax) # If the space is
+ # unavailable, i.e.
+ # already in use.. Go
+ je next_location # to the next one.
+
+ cmpq %rdx, %rcx # If the slot is available, check if
+ jle allocate_here # it's big enough.
+
+ next_location:
+ addq $HEADER_SIZE, %rax # Total size of the memory region is the
+ # sum of the size requested (currently
+ # at %rdx), plus the 16 bytes for the
+ addq %rdx, %rax # header.
+
+ jmp alloc_loop_begin # Go look at the next location
+
+ allocate_here: # If we've made it here, that means that
+ # the region header of the region to
+ # allocate is in %rax
+
+ # Mark space as unavailable
+ movq $UNAVAILABLE, HDR_AVAIL_OFFSET(%rax)
+ addq $HEADER_SIZE, %rax # move %rax past the header, so it
+ # points to the usable memory. Such
+ # address is returned to the user.
+
+ # Normal function return
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+ move_break: # We have exhausted all addressable memory, we need to
+ # get more from Linux
+ # %rbx holds the current endpoint of the data, and
+ # %rcx its size.
+
+ addq $HEADER_SIZE, %rbx # We need to increase %rbx to where we _want_
+ # memory to end. So we account for the header
+ addq %rcx, %rbx # and the user's requested size
+
+ # Ask Linux for more memory
+
+ # We'll need the values in these registers, so save them...
+ pushq %rax
+ pushq %rbx
+ pushq %rcx
+
+ movq $SYS_BRK, %rax # Set new break by calling brk()
+ movq %rbx, %rdi # x86_64 uses %rdi for first parameter
+ syscall
+
+ # brk() returns 0 for error or the address we asked for (or larger if it
+ # needs to be rounded up). We don't really care here where it ends up
+ # setting the break as long as it isn't 0.
+
+ cmpq $0, %rax # Check for errors
+ je error
+
+ # Restore our registers
+ popq %rcx
+ popq %rbx
+ popq %rax
+
+ # Set this memory as unavailable since we are about to give it away
+ movq $UNAVAILABLE, HDR_AVAIL_OFFSET(%rax)
+ movq %rcx, HDR_SIZE_OFFSET(%rax) # Set memory size
+
+ addq $HEADER_SIZE, %rax # Set %rax to the address being
+ # returned to the user (user
+ # doesn't know anything about the headers
+
+ movq %rbx, current_break # Save the current break. In
+ # reality it may be larger due
+ # rounding, but we don't care
+ # about memory footprint here
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+ error:
+ movq $0, %rax # Return 0 on error
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+##### END OF allocate ######
+
+## deallocate ##
+#
+# Give back a region of memory to the pool after user is done
+# with it
+#
+# Parameter: Address of the memory to be freed
+# No return value
+#
+# The memory address returned to the user starts at 2 words beyond its header,
+# all we need to do here is mark the memory slot as free (available).
+# By now we don't care about moving the break back.
+.globl deallocate
+.type deallocate, @function
+
+# Stack position of the memory region to be free (function's parameter)
+.equ ST_MEMORY_SEG, 8 # We are not saving %rbp here so we just need to skip ret
+ # address
+
+deallocate:
+ # Function is too simple, no need for fancy function stuff
+
+ # Get the address of the memory to free (Normally this is 16(%rbp), but
+ # since we didn't push %rbp or move %rsp to %rbp, we can just do 8(%rsp)
+ movq ST_MEMORY_SEG(%rsp), %rax
+
+ # Get the pointer to the beginning of the region (i.e. to the header)
+ subq $HEADER_SIZE, %rax
+
+ # Mark it as available
+ movq $AVAILABLE, HDR_AVAIL_OFFSET(%rax)
+ ret
+##### END OF deallocate #####
diff --git a/PGU/CHAP9/read-records.s b/PGU/CHAP9/read-records.s
new file mode 100644
index 0000000..01384a0
--- /dev/null
+++ b/PGU/CHAP9/read-records.s
@@ -0,0 +1,86 @@
+# Read records previously written in file.dat, by write-records software
+
+.include "linux.s"
+.include "record-def.s"
+
+.section .data
+ filename:
+ .ascii "test.dat\0"
+ record_buffer_ptr:
+ .long 0
+
+.section .text
+
+.globl _start
+
+_start:
+ # Stack locations for INPUT and OUTPUT FDs
+ .equ ST_INPUT_DESCRIPTOR, -8
+ .equ ST_OUTPUT_DESCRIPTOR, -16
+
+ movq %rsp, %rbp
+ subq $16, %rsp # Save space in the stack for FDs
+
+ call allocate_init # Initialize our memory
+
+ # allocate buffer
+ pushq $RECORD_SIZE
+ call allocate
+ movq %rax, record_buffer_ptr
+
+ # Open data file
+ movq $SYS_OPEN, %rax
+ movq $filename, %rdi
+ movq $0, %rsi # Open for read only
+ movq $0666, %rdx
+ syscall
+
+ # Save FD
+ movq %rax, ST_INPUT_DESCRIPTOR(%rbp)
+
+ # Yes, STDOUT is always 1, but if I want to change the output location
+ # later, I don't need to change everywhere...
+ movq $STDOUT, ST_OUTPUT_DESCRIPTOR(%rbp)
+
+record_read_loop:
+ pushq ST_INPUT_DESCRIPTOR(%rbp)
+ pushq record_buffer_ptr
+ call read_record
+ addq $16, %rsp # Cleanup stack
+
+ # All records are RECORD_SIZE size, if we didn't get this amount of
+ # bytes from read function, we either are at EOF or we hit an error.
+ cmpq $RECORD_SIZE, %rax
+ jne finished_reading
+
+ # We are ok, so print the first name in the record
+ movq record_buffer_ptr, %rax
+ addq $RECORD_FIRSTNAME, %rax # Seek offset of the firstname in the
+ # buffer
+ pushq %rax
+ call count_chars
+ addq $8, %rsp # Cleanup stack
+
+ # Write name to OUTPUT
+ movq %rax, %rdx # Returned record size, used as argument to
+ # write()
+
+ movq record_buffer_ptr, %rsi
+ addq $RECORD_FIRSTNAME, %rsi
+ movq ST_OUTPUT_DESCRIPTOR(%rbp), %rdi
+ movq $SYS_WRITE, %rax
+ syscall
+
+ pushq ST_OUTPUT_DESCRIPTOR(%rbp)
+ call write_newline
+ addq $8, %rsp
+
+ jmp record_read_loop
+
+ # Free buffer
+ pushq record_buffer_ptr
+ call deallocate
+finished_reading:
+ movq $SYS_EXIT, %rax
+ movq $0, %rdi
+ syscall
diff --git a/PGU/CHAP9/read_write.s b/PGU/CHAP9/read_write.s
new file mode 100644
index 0000000..d574013
--- /dev/null
+++ b/PGU/CHAP9/read_write.s
@@ -0,0 +1,62 @@
+.include "record-def.s"
+.include "linux.s"
+
+# Read function
+# Reads a record from the file descriptor
+# and writes it into the buffer passed
+
+# STACK VARS - Used for both read and write functions. They don't share the
+# location, but the arguments are passed in the same position
+# for both, so, no need to create different location vars.
+
+.equ ST_BUFFER, 16 # Ret address is at %rsp+8
+.equ ST_FILEDES, 24
+
+.section .text
+
+.globl read_record
+.type read_record, @function
+
+read_record:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # READ A RECORD
+ pushq %rdi
+ movq ST_FILEDES(%rbp), %rdi
+ movq ST_BUFFER(%rbp), %rsi
+ movq $RECORD_SIZE, %rdx
+ movq $SYS_READ, %rax
+ syscall
+
+ # NOTE: %rax has the return value, which we will give back
+ # to our caller
+
+ popq %rdi
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+.globl write_record
+.type write_record, @function
+
+write_record:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # WRITE A RECORD
+ pushq %rdi
+ movq ST_FILEDES(%rbp), %rdi
+ movq ST_BUFFER(%rbp), %rsi
+ movq $RECORD_SIZE, %rdx
+ movq $SYS_WRITE, %rax
+ syscall
+
+ # NOTE: %rax has the return value, which we will give back
+ # to our caller
+ popq %rdi
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/CHAP9/record-def.s b/PGU/CHAP9/record-def.s
new file mode 100644
index 0000000..9e5274d
--- /dev/null
+++ b/PGU/CHAP9/record-def.s
@@ -0,0 +1,7 @@
+# Define offsets within a record
+
+.equ RECORD_FIRSTNAME, 0
+.equ RECORD_LASTNAME, 40
+.equ RECORD_ADDRESS, 80
+.equ RECORD_AGE, 320 # Use 8 bytes for age, because it's
+.equ RECORD_SIZE, 328 # simpler to deal with whole words
diff --git a/PGU/CHAP9/write-newline.s b/PGU/CHAP9/write-newline.s
new file mode 100644
index 0000000..e916379
--- /dev/null
+++ b/PGU/CHAP9/write-newline.s
@@ -0,0 +1,29 @@
+# Just write a newline (\n) to STDOUT
+
+.include "linux.s"
+.type write_newline, @function
+.globl write_newline
+
+.section .data
+
+newline:
+ .ascii "\n"
+
+.section .text
+ .equ ST_FILEDES, 16
+
+write_newline:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq $SYS_WRITE, %rax
+ movq ST_FILEDES(%rbp), %rdi
+ movq $newline, %rsi
+ movq $1, %rdx
+ syscall
+
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+
diff --git a/PGU/OLD/asm/exit.s b/PGU/OLD/asm/exit.s
new file mode 100644
index 0000000..b1ef45b
--- /dev/null
+++ b/PGU/OLD/asm/exit.s
@@ -0,0 +1,17 @@
+.section .data
+
+.section .text
+
+.globl _start
+
+_start:
+
+ # %eax should contain syscall number
+ # to be executed (exit syscall num: 1)
+ movl $1, %eax
+
+ # %ebx contains syscall argument
+ movl $5, %ebx
+
+ #Call syscall interrupt
+ int $0x80
diff --git a/PGU/OLD/asm/max.c b/PGU/OLD/asm/max.c
new file mode 100644
index 0000000..5b4c37a
--- /dev/null
+++ b/PGU/OLD/asm/max.c
@@ -0,0 +1,27 @@
+int main(void)
+{
+
+ static int list[] = {10,20,30,40,5,50,60,70,80,90,0};
+ int i, ret;
+
+ ret = list[0];
+ i = 0;
+
+ /*
+ for (i = 0; list[i] != 0; i++) {
+ if (list[i] < ret)
+ ret = list[i];
+ }
+ */
+ while (1) {
+ i++;
+
+ if (list[i] == 0)
+ return ret;
+
+ if (ret > list[i])
+ ret = list[i];
+ }
+
+ return ret;
+}
diff --git a/PGU/OLD/asm/max.s b/PGU/OLD/asm/max.s
new file mode 100644
index 0000000..21f750a
--- /dev/null
+++ b/PGU/OLD/asm/max.s
@@ -0,0 +1,39 @@
+ .file "max.c"
+ .text
+ .globl main
+ .type main, @function
+main:
+.LFB0:
+ .cfi_startproc
+ movl $list.1406+8, %ecx
+ movl $20, %edx
+ movl $10, %eax
+.L2:
+ cmpl %edx, %eax
+ cmovg %edx, %eax
+ addl $4, %ecx
+ movl -4(%ecx), %edx
+ testl %edx, %edx
+ jne .L2
+ rep ret
+ .cfi_endproc
+.LFE0:
+ .size main, .-main
+ .section .rodata
+ .align 32
+ .type list.1406, @object
+ .size list.1406, 44
+list.1406:
+ .long 10
+ .long 20
+ .long 30
+ .long 40
+ .long 5
+ .long 50
+ .long 60
+ .long 70
+ .long 80
+ .long 90
+ .long 0
+ .ident "GCC: (GNU) 6.2.1 20160916 (Red Hat 6.2.1-2)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/PGU/OLD/asm/maximum b/PGU/OLD/asm/maximum
new file mode 100644
index 0000000..4c7b855
--- /dev/null
+++ b/PGU/OLD/asm/maximum
Binary files differ
diff --git a/PGU/OLD/asm/maximum.s b/PGU/OLD/asm/maximum.s
new file mode 100644
index 0000000..cb6394c
--- /dev/null
+++ b/PGU/OLD/asm/maximum.s
@@ -0,0 +1,14 @@
+#%edi holds the current position
+#%ebx hold the current highest value
+#%eax hold the current element being examined
+
+.section.data data_items:
+.long 3, 4, 5, 65, 44, 36, 99, 6, 7, 8, 9, 0
+ data_end:.section.text.globl _start
+ _start:movl $ (data_items), %edi
+movl (%edi), %eax
+movl % eax, %ebx
+start_loop:cmpl $ (data_end), %edi
+je loop_exit
+addl $4, %edi
+movl (%edi), %eax cmpl % ebx, %eax jle start_loop movl % eax, %ebx jmp start_loop loop_exit:movl $1, %eax int $0x80
diff --git a/PGU/OLD/chapter3/exit b/PGU/OLD/chapter3/exit
new file mode 100644
index 0000000..a70d0fd
--- /dev/null
+++ b/PGU/OLD/chapter3/exit
Binary files differ
diff --git a/PGU/OLD/chapter3/exit.s b/PGU/OLD/chapter3/exit.s
new file mode 100644
index 0000000..632ebed
--- /dev/null
+++ b/PGU/OLD/chapter3/exit.s
@@ -0,0 +1,70 @@
+# A useless program, which the only thing this shit does is call exit syscall
+# The exit status code can be read using
+
+# `echo $?` on shell, which will show the exit status of the last program run.
+
+
+# %eax holds the system call number
+# %ebx holds the return status
+
+
+# Assembler directives (or pseudo-operations).
+#
+# Everything starting with a period, is an instruction to the assembler itself.
+# They are handled by the assembler program, not actually executed by the
+# computer.
+
+# .section command breaks the program down into sections.
+
+# .data section lists any memory storage which will be needed for data
+.section .data
+
+# .text section lists the program instructions
+.section .text
+
+# Instructs the assembler that _start is "important to remember".
+# _start is a symbol, which is going to be replaced by something else either
+# during assembly or linking
+
+# Symbols are generally used to mark locations of programs or data, so you can
+# refer to them by name instead of by location number
+
+# .globl means that the assembler should not discard this symbol after assembly,
+# because the linker will need it.
+
+# _start is a special symbol that always needs to be marked with .globl, because
+# it marks the location of the start of the program.
+
+# If the program is not marked this way, when the computer loads the program, it
+# won't know where to begin running the program.
+
+.globl _start
+
+# Defines the value of _start label. Label == a symbol followed by a colon.
+# Labels defines a symbol's value.
+
+# Labels tell the assembler to make the symbol's value be wherever the next
+# instruction or data element will be.
+
+_start:
+
+# different from the book, I'm using x86_64 instructions and its registers, so,
+# instead of using %eax and %ebx, I'm using %rax and %rbx directly. The movl
+# instruction needed to be changed to movq (move quad) to adapt to the 64-bit
+# registers
+# mov: (move) 16-bit
+# movl: (move long) 32-bit
+# movq: (move quad) 64-bit
+
+#ins $(val), (dest) == immediate mode
+movq $1, %rax # Move value 1 into %eax register
+ # %eax will hold the syscall number
+ # by the linux's calling convention
+
+movq $100, %rbx # Move value 0 into %ebx register
+ # %ebx will hold the exit() syscall
+ # argument.
+
+int $0x80 # Interrupt 0x80 will wake up the kernel
+ # execute the syscall loaded into %eax
+
diff --git a/PGU/OLD/chapter3/max.s b/PGU/OLD/chapter3/max.s
new file mode 100644
index 0000000..6ebc906
--- /dev/null
+++ b/PGU/OLD/chapter3/max.s
@@ -0,0 +1,42 @@
+# Given a list of X numbers, find the maximum number of the list and use it as
+# the argument of exit() syscall
+
+# %rbx holds the maximum number through the whole scanning process
+# %rax holds the current element being examined
+# %rdi holds the currend position in the list
+# zero marks the end of the list
+
+# Data section, now containing some statically created data
+.section .data
+
+# Just a label to refer to the first item in the list
+data_items:
+ # "Type" of memory location to be reserved. In quotes because it just
+ # says how many bytes should be reserved to each item, not the 'type'
+ # itself
+ # Reserves 10 '8byte' (quad) slots consecutive in memory,
+ .quad 3,10,9,230,66,77,23,66,12,69,0
+
+.section .text
+
+.globl _start
+
+_start:
+ movq $0, %rdi
+ movq data_items(, %rdi,8), %rax
+ movq %rax, %rbx
+
+ start_loop:
+ cmpq $0, %rax
+ je loop_exit
+ incq %rdi
+ movq data_items(,%rdi,8), %rax
+ cmpq %rbx, %rax
+ jle start_loop
+ movq %rax, %rbx
+ jmp start_loop
+
+
+ loop_exit:
+ movq $1, %rax
+ int $0x80
diff --git a/PGU/OLD/chapter3/min.s b/PGU/OLD/chapter3/min.s
new file mode 100644
index 0000000..9179be7
--- /dev/null
+++ b/PGU/OLD/chapter3/min.s
@@ -0,0 +1,52 @@
+# This code has been originally copied from max.s
+
+# It has been modified to:
+# - Find the smallest value, instead of the largest
+# - Use Start/End addresses to delimit the boundaries of the number list
+#
+# %rax - holds the current element being examined
+# %rbx - Holds the smallest number
+
+.section .data
+
+# This version has 2 labels, one to point to the start of the list, and another
+# to point to the address right after it, so we can use it to search the list
+# boundary.
+
+data_items:
+ .quad 234,10,9,230,66,77,23,66,101,69,100
+data_end:
+
+.section .text
+
+.globl _start
+
+_start:
+
+# Using immediate mode with a label, will give you the ADDRESS of the
+# instruction/data it points to. Once the label itself contains an ADDRESS, the
+# immediate mode will give you the ADDRESS itself.
+
+# Using direct mode with a label, will give you the DATA into the address the
+# label points to. Once the label itself contains an address, the direct mode,
+# as expected will give you the DATA into the address pointed by the label.
+ movq $data_items, %rax
+ cmpq $data_end, %rax # We need this check here in case
+ je exit_loop_empty # the items list is empty
+ movq (%rax), %rbx
+
+ loop_start:
+ addq $8, %rax # We are using QuadWords, so 8 bytes
+ cmpq $data_end, %rax
+ je exit_loop
+
+ cmpq (%rax), %rbx
+ jle loop_start
+ movq (%rax), %rbx
+ jmp loop_start
+
+ exit_loop_empty:
+ movq $255, %rbx
+ exit_loop:
+ movq $1, %rax
+ int $0x80
diff --git a/PGU/OLD/chapter4/call_power.c b/PGU/OLD/chapter4/call_power.c
new file mode 100644
index 0000000..b6bb7e0
--- /dev/null
+++ b/PGU/OLD/chapter4/call_power.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int power(int a, int b);
+
+int main(void) {
+ int a = 2;
+ int b = 6;
+
+ printf("Power == %d\n", power(2, 6));
+
+ return 0;
+}
diff --git a/PGU/OLD/chapter4/factorial.s b/PGU/OLD/chapter4/factorial.s
new file mode 100644
index 0000000..749f57e
--- /dev/null
+++ b/PGU/OLD/chapter4/factorial.s
@@ -0,0 +1,73 @@
+##################################################################
+# Calculate the factorial of a number, using recursive functions #
+##################################################################
+
+
+#
+# %rbx holds the number to factor
+#
+.section .data
+
+.section .text
+
+.globl _start
+_start:
+ pushq $5
+ call factorial2
+ addq $8, %rsp # Turn back the stack pointer
+ # Not really needed here, but good practice
+ movq %rax, %rbx
+ movq $1, %rax
+ int $0x80
+
+.type factorial, @function
+
+# This function is garbage, can be much more clean than this shit.
+
+factorial:
+ pushq %rbp # Regular initial function stuff
+ movq %rsp, %rbp # Save %rbp and reset it to %rsp
+
+ movq 16(%rbp), %rbx # Get the argument passed into %rbx
+ movq %rbx, %rcx # Copy it to %rcx and decrement it
+ decq %rcx # here. %rcx will be the next element in the
+ # factorial.
+ #
+ cmpq $1, %rcx # Compare it to 1 and exit if true, we are at
+ je exit_factorial # the end of the factorial
+
+ pushq %rbx # If not one, save the original argument in the
+ pushq %rcx # stack and push the next value as argument to
+ call factorial # the recursive call
+ popq %rcx # pop value to restore stack pointer
+ popq %rbx # restore %rbx and multiply it
+ imul %rax, %rbx # by the result
+
+exit_factorial:
+ movq %rbx, %rax # Move the result to %rax
+ movq %rbp, %rsp # And do standard clean up before
+ popq %rbp # returning.
+ ret
+
+# This is a clean version after extra thought on this
+
+.type factorial2, @function
+factorial2:
+ pushq %rbp # Basic function setup, save %rbp and
+ movq %rsp, %rbp # setup it to current %rsp
+
+ movq 16(%rbp), %rax # Get the argument passed into
+ cmpq $1, %rax #
+ je factorial2_end # We are at the last element in the factorial
+ # Just return it
+ decq %rax
+ pushq %rax
+ call factorial2
+ movq 16(%rbp), %rbx
+ imulq %rbx, %rax
+
+factorial2_end:
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
diff --git a/PGU/OLD/chapter4/libpower.s b/PGU/OLD/chapter4/libpower.s
new file mode 100644
index 0000000..5172cda
--- /dev/null
+++ b/PGU/OLD/chapter4/libpower.s
@@ -0,0 +1,48 @@
+# Simple example of functions in ASM, following System V ABI
+# and C calling convention
+
+# Everything is stored in registers, so, we have nothing in data section
+
+####################
+# #
+# Function power() #
+# #
+####################
+
+# Remember the return address (where the program should keep executing after
+# function return), is also pushed into the stack by the 'call' command.
+
+# Remember, in x86_64 architecture, the Stack grows 'downwards', so, every time
+# we want to look back in the stack, we need to add to the current stack
+# pointer, other than subtract.
+
+# Ex:
+# 56 <- stack 'bottom'
+# 48 pushq
+# 40 pushq
+# 32 <- %rsp (top of the stack)
+
+.type power, @function
+power:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq 16(%rbp), %rcx # Holds the Base number. 16 because:
+ # Current %rsp (pushq %rbp) plus the
+ # implicit return address pushed by
+ # the call command
+
+ movq 24(%rbp), %rbx # Holds the power (pushed first before
+ # function call
+ movq %rcx, %rax
+
+loop:
+ cmpq $1, %rbx
+ je return
+ imul %rcx, %rax
+ decq %rbx
+ jmp loop
+
+return:
+ movq %rbp, %rsp
+ popq %rbp
+ ret
diff --git a/PGU/OLD/chapter4/power.s b/PGU/OLD/chapter4/power.s
new file mode 100644
index 0000000..fe89eae
--- /dev/null
+++ b/PGU/OLD/chapter4/power.s
@@ -0,0 +1,90 @@
+# Simple example of functions in ASM, following System V ABI
+# and C calling convention
+
+# Everything is stored in registers, so, we have nothing in data section
+.section .data
+
+.section .text
+
+.globl _start
+
+_start:
+ pushq $3 # Second argument
+ pushq $2 # First argument
+ call power # call function power()
+
+ addq $16, %rsp # Remove arguments from the stack
+ # Could have popped'em, but we don't
+ # need them anymore, so, just move
+ # the stack pointer back
+
+ pushq %rax # Save return value of power()
+
+# Call power () again
+ pushq $2 # Push second argument
+ pushq $5 # Push first argument
+ call power
+
+ addq $16, %rsp # Move stack pointer back
+
+ popq %rbx # Second answer is already in %eax
+ # (returned from power), first answer
+ # was pushed into the stack before, so,
+ # just pop it into %ebx.
+
+ addq %rax, %rbx # Sum up both results (and %ebx is already the
+ # exit()'s return value
+
+# Call exit()
+
+ movq $1, %rax
+ int $0x80
+
+
+
+
+####################
+# #
+# Function power() #
+# #
+####################
+
+# Remember the return address (where the program should keep executing after
+# function return), is also pushed into the stack by the 'call' command.
+
+# Remember, in x86_64 architecture, the Stack grows 'downwards', so, every time
+# we want to look back in the stack, we need to add to the current stack
+# pointer, other than subtract.
+
+# Ex:
+# 56 <- stack 'bottom'
+# 48 pushq
+# 40 pushq
+# 32 <- %rsp (top of the stack)
+
+#Tread symbol 'power' as a function
+.type power,@function
+
+power:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq 16(%rbp), %rcx # Holds the Base number. 16 because:
+ # Current %rsp (pushq %rbp) plus the
+ # implicit return address pushed by
+ # the call command
+
+ movq 24(%rbp), %rbx # Holds the power (pushed first before
+ # function call
+ movq %rcx, %rax
+
+loop:
+ cmpq $1, %rbx
+ je return
+ imul %rcx, %rax # The result is already stored in %rax
+ decq %rbx
+ jmp loop
+
+return:
+ movq %rbp, %rsp
+ popq %rbp
+ ret