diff options
| author | mo khan <mo@mokhan.ca> | 2025-01-23 12:09:22 -0700 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-01-23 12:09:22 -0700 |
| commit | c8ac898c9ec045d0de769886e5306dc177914527 (patch) | |
| tree | 4aa57bb762572a61c977297f97962c402d7773d5 /assignments | |
| parent | be0232e94c981284c5cd8f2c6013c252ebeb98d0 (diff) | |
Update the things
Diffstat (limited to 'assignments')
| -rw-r--r-- | assignments/3-solution.md | 17 | ||||
| -rw-r--r-- | assignments/3/Makefile | 5 | ||||
| -rw-r--r-- | assignments/3/max_min.asm | 158 | ||||
| -rw-r--r-- | assignments/3/max_min.s | 33 |
4 files changed, 208 insertions, 5 deletions
diff --git a/assignments/3-solution.md b/assignments/3-solution.md index 3403327..3ac8b91 100644 --- a/assignments/3-solution.md +++ b/assignments/3-solution.md @@ -6,8 +6,16 @@ Choose ONE exercise each from Chapters 6, 7, and 8 Chapter 6: -> 13. Write a complete assembly language program (including all necessary pseudo-ops) that reads in a series of integers, one at a time, and outputs the largest and smallest values. The input will consist of a list of integer values +> 13. Write a complete assembly language program (including all necessary +> pseudo-ops) that reads in a series of integers, one at a time, and outputs +> the largest and smallest values. The input will consist of a list of integer +> values +```assembly +!include assignments/3/max_min.s +``` + +<!-- I wrote the following C code and then used the GNU C Compiler to convert the C code into Assembly code for my machine. Below is the C code, compiler command, and final assembly code. @@ -26,6 +34,7 @@ main.s ```assembly !include assignments/3/main.s ``` +--> Chapter 7: @@ -129,3 +138,9 @@ $ ruby caesar.rb | Ciphertext | RTAJ TZY FY IFBS | | Plaintext | MOVE OUT AT DAWN | ``` + +References: + +* https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ +* https://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html +* https://cs.lmu.edu/~ray/notes/gasexamples/ diff --git a/assignments/3/Makefile b/assignments/3/Makefile index 75f6584..1a83223 100644 --- a/assignments/3/Makefile +++ b/assignments/3/Makefile @@ -16,3 +16,8 @@ manual: max_min.s as --64 -o max_min.o max_min.s ld -o max_min.exe max_min.o ./max_min.exe + +manual_ai: max_min.asm + as --64 -o max_min.o max_min.asm + ld -o max_min.exe max_min.o + ./max_min.exe diff --git a/assignments/3/max_min.asm b/assignments/3/max_min.asm new file mode 100644 index 0000000..4487fcc --- /dev/null +++ b/assignments/3/max_min.asm @@ -0,0 +1,158 @@ +.section .data +largest_msg: .asciz "Max: " +smallest_msg: .asciz "The smallest number is: " +newline: .asciz "\n" +temp_input: .space 32 # Buffer for input string +largest: .quad 0 +smallest: .quad 0 +initialized: .byte 0 # Flag to check if smallest/largest are initialized + +.section .text +.globl _start + +_start: + # Initialize the largest and smallest values + movq $0, largest + movq $0, smallest + movb $0, initialized # Mark as uninitialized + +read_input: + # Read a line of input from stdin + movq $0, %rax # syscall: read + movq $0, %rdi # file descriptor: stdin + lea temp_input(%rip), %rsi # buffer to store input + movq $32, %rdx # size of input buffer + syscall + + # Check if input is empty (EOF) + cmpq $0, %rax + je print_results + + # Null-terminate the input string + lea temp_input(%rip), %rdi # Load base address of temp_input + addq %rax, %rdi # Add offset to the base address + movb $0, (%rdi) # Null-terminate the string + + # Convert the input string to an integer + lea temp_input(%rip), %rsi + call string_to_int + movq %rax, %rdi # Store integer in %rdi + + # Check for termination (sentinel value -1) + cmpq $-1, %rdi + je print_results + + # Check if largest/smallest are initialized + cmpb $0, initialized(%rip) + jne compare_values + + # Initialize largest and smallest with the first input value + movq %rdi, largest(%rip) + movq %rdi, smallest(%rip) + movb $1, initialized(%rip) # Mark as initialized + jmp read_input + +compare_values: + # Update the largest value + movq largest(%rip), %rax + cmpq %rdi, %rax + jge check_smallest + movq %rdi, largest(%rip) + +check_smallest: + # Update the smallest value + movq smallest(%rip), %rax + cmpq %rdi, %rax + jle read_input + movq %rdi, smallest(%rip) + jmp read_input + +print_results: + # Print the largest value + movq $1, %rax # syscall: write + movq $1, %rdi # file descriptor: stdout + lea largest_msg(%rip), %rsi + movq $5, %rdx # length of message + syscall + + movq largest(%rip), %rax # Load the largest value + call print_integer + + # Print newline + movq $1, %rax + movq $1, %rdi + lea newline(%rip), %rsi + movq $1, %rdx + syscall + + # Print the smallest value + movq $1, %rax + movq $1, %rdi + lea smallest_msg(%rip), %rsi + movq $25, %rdx + syscall + + movq smallest(%rip), %rax # Load the smallest value + call print_integer + + # Print newline + movq $1, %rax + movq $1, %rdi + lea newline(%rip), %rsi + movq $1, %rdx + syscall + + # Exit program + movq $60, %rax # syscall: exit + xorq %rdi, %rdi + syscall + +string_to_int: + # Convert null-terminated string at %rsi to integer in %rax + xorq %rax, %rax # Clear %rax (result) + xorq %rbx, %rbx # Clear %rbx (temporary register) + +convert_loop: + movb (%rsi), %bl # Load next character + cmpb $0, %bl # Check for null terminator + je convert_done + subb $48, %bl # Convert ASCII to integer + imulq $10, %rax # Multiply result by 10 + addq %rbx, %rax # Add the current digit + incq %rsi # Move to the next character + jmp convert_loop + +convert_done: + ret + +print_integer: + # Convert integer in %rax to string and print it + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + + movq $10, %rbx # Base 10 divisor + xorq %rcx, %rcx # Counter for digits + movq %rax, %rdx # Copy number to %rdx + + # Convert digits to string in reverse order +convert_digit: + xorq %r8, %r8 # Clear temporary + divq %rbx # Divide %rdx by 10, remainder in %rax + addb $48, %al # Convert remainder to ASCII + movb %al, -1(%rbp,%rcx) # Store digit + incq %rcx # Increment digit count + testq %rdx, %rdx # Check if quotient is 0 + jne convert_digit + + # Print the digits + movq $1, %rax # syscall: write + movq $1, %rdi # file descriptor: stdout + lea -1(%rbp,%rcx), %rsi # Start of digits + movq %rcx, %rdx # Length of string + syscall + + movq %rbp, %rsp + popq %rbp + ret + diff --git a/assignments/3/max_min.s b/assignments/3/max_min.s index 1c0e84a..cad40ac 100644 --- a/assignments/3/max_min.s +++ b/assignments/3/max_min.s @@ -2,11 +2,11 @@ .text _start: - # write(1, message, 13) + # write(1, greeting, 16) mov $1, %rax # system call 1 is write mov $1, %rdi # file handle 1 is stdout - mov $message, %rsi # address of string to output - mov $13, %rdx # number of bytes + mov $greeting, %rsi # address of string to output + mov $16, %rdx # number of bytes syscall # invoke operating system to do the write # read(0, input, 3) @@ -16,6 +16,27 @@ _start: mov $4, %rdx # number of bytes syscall # invoke operating system to do the write + # write(1, max_message, 4) + mov $1, %rax # system call 1 is write + mov $1, %rdi # file handle 1 is stdout + mov $max_message, %rsi # address of string to output + mov $5, %rdx # number of bytes + syscall # invoke operating system to do the write + + # write(1, input, 4) + mov $1, %rax # system call 1 is write + mov $1, %rdi # file handle 1 is stdout + mov $input, %rsi # address of string to output + mov $4, %rdx # number of bytes + syscall # invoke operating system to do the write + + # write(1, min_message, 4) + mov $1, %rax # system call 1 is write + mov $1, %rdi # file handle 1 is stdout + mov $min_message, %rsi # address of string to output + mov $5, %rdx # number of bytes + syscall # invoke operating system to do the write + # write(1, input, 4) mov $1, %rax # system call 1 is write mov $1, %rdi # file handle 1 is stdout @@ -29,5 +50,9 @@ _start: syscall # invoke operating system to exit .data -message: .ascii "Hello, world\n" +greeting: .ascii "Enter numbers: \n" +max_message: .ascii "Max: " +min_message: .ascii "Min: " input: .word 0 +max: .word 0 +min: .word 0 |
