├── Fibonacci ├── fib.py ├── fib.s ├── fillable_fib.s ├── run_fib.sh └── spiral.png ├── GCD ├── euclid.png ├── fillable_gcd.s ├── gcd.py ├── gcd.s └── run_gcd.sh ├── README.md └── StackOverflow ├── overflow.s ├── overflow_fillable.s ├── run_overflow.sh ├── show_overflow.py └── show_stack.py /Fibonacci/fib.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import time 3 | import threading 4 | from PIL import Image, ImageTk 5 | from math import pi, sin, cos 6 | 7 | def read_fibonacci_from_file(label, canvas, circle, root, spiral_distance): 8 | angle = 0 9 | last_number = None 10 | same_number_count = 0 11 | circle_radius = 50 # Should be the same as in main() 12 | 13 | while same_number_count < 5: 14 | try: 15 | with open("nums.txt", "r") as file: 16 | for last_line in file: 17 | pass 18 | current_number = last_line.strip() 19 | 20 | if current_number == last_number: 21 | same_number_count += 1 22 | else: 23 | same_number_count = 0 24 | last_number = current_number 25 | 26 | label.config(text=current_number) 27 | x = root.winfo_width() / 2 + spiral_distance * cos(angle) 28 | y = root.winfo_height() / 2 + spiral_distance * sin(angle) 29 | 30 | # Update label position 31 | label.place(x=x, y=y, anchor="center") 32 | 33 | # Update circle position 34 | canvas.coords(circle, x - circle_radius, y - circle_radius, x + circle_radius, y + circle_radius) 35 | 36 | angle += pi / 4 37 | except Exception as e: 38 | print(f"Error reading file: {e}") 39 | label.config(text="Error") 40 | time.sleep(0.1) 41 | 42 | 43 | def main(): 44 | root = tk.Tk() 45 | root.title("Fibonacci Sequence") 46 | 47 | window_width = root.winfo_screenwidth() 48 | window_height = root.winfo_screenheight() 49 | root.geometry(f"{window_width}x{window_height}+0+0") 50 | 51 | bg_image_path = "spiral.png" 52 | bg_image = Image.open(bg_image_path) 53 | bg_photo = ImageTk.PhotoImage(bg_image) 54 | 55 | canvas = tk.Canvas(root, width=window_width, height=window_height) 56 | canvas.pack(fill="both", expand=True) 57 | canvas.create_image(window_width // 2, window_height // 2, image=bg_photo) 58 | 59 | # Create a canvas circle for the background of the number 60 | circle_radius = 50 # Adjust the radius as needed 61 | circle = canvas.create_oval( 62 | window_width // 2 - circle_radius, 63 | window_height // 2 - circle_radius, 64 | window_width // 2 + circle_radius, 65 | window_height // 2 + circle_radius, 66 | fill='pink' 67 | ) 68 | 69 | # Create a label for the Fibonacci number 70 | fib_label = tk.Label(root, text="", font=("Helvetica", 35), fg='black', bg='pink') 71 | fib_label.place(x=window_width // 2, y=window_height // 2, anchor="center") 72 | 73 | spiral_distance = 200 74 | threading.Thread(target=read_fibonacci_from_file, args=(fib_label, canvas, circle, root, spiral_distance), daemon=True).start() 75 | root.mainloop() 76 | 77 | 78 | if __name__ == "__main__": 79 | main() 80 | -------------------------------------------------------------------------------- /Fibonacci/fib.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi 3 | 4 | .section .data 5 | filename: .asciz "nums.txt" 6 | write_mode: .asciz "w" 7 | format_str: .asciz "%d\n" 8 | format_str_result: .asciz "Fibonacci Number: %d\n" 9 | 10 | .section .text 11 | 12 | print_num_to_file: 13 | push {lr} 14 | push {r0-r5} 15 | 16 | mov r5, r0 17 | 18 | // Open the file for writing 19 | ldr r0, =filename 20 | ldr r1, =write_mode 21 | bl fopen 22 | mov r4, r0 // Store the file pointer in r4 23 | 24 | // Check if fopen succeeded 25 | cmp r4, #0 26 | beq close_file 27 | 28 | // Write the number to the file 29 | mov r0, r4 30 | ldr r1, =format_str 31 | mov r2, r5 32 | bl fprintf 33 | 34 | // Close the file 35 | close_file: 36 | mov r0, r4 37 | bl fclose 38 | 39 | pop {r0-r5} 40 | pop {pc} 41 | 42 | fibonacci: 43 | push {lr} 44 | 45 | // Base case: if n <= 1, return n 46 | cmp r0, #1 47 | ble end_fib 48 | 49 | // Recursive case: return fib(n - 1) + fib(n - 2); 50 | push {r0} // Save the current value of n 51 | sub r0, r0, #1 52 | bl fibonacci // Recursive call fibonacci(n - 1) 53 | 54 | pop {r1} // Restore the original n 55 | push {r0} // Save fibonacci(n - 1) 56 | sub r1, r1, #2 57 | mov r0, r1 58 | bl fibonacci // Recursive call fibonacci(n - 2) 59 | pop {r1} // Get fibonacci(n - 1) 60 | 61 | add r0, r0, r1 // Add fibonacci(n - 1) + fibonacci(n - 2) 62 | 63 | end_fib: 64 | pop {pc} 65 | 66 | main: 67 | push {r4-r7, lr} 68 | 69 | // Check if argument count (argc) is correct 70 | cmp r0, #2 // Expecting 2 arguments (program name and n) 71 | blt exit 72 | 73 | // Convert argument string to integer 74 | ldr r0, [r1, #4] // Load address of second argument (n value) 75 | bl atoi // Convert string to integer 76 | mov r4, r0 77 | 78 | // Calculate the nth Fibonacci number 79 | mov r0, r4 80 | bl fibonacci 81 | 82 | // Print fib result to our file 83 | bl print_num_to_file 84 | 85 | exit: 86 | // Exit 87 | mov r0, #0 88 | pop {r4-r7, pc} 89 | 90 | 91 | .section .note.GNU-stack 92 | -------------------------------------------------------------------------------- /Fibonacci/fillable_fib.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi 3 | 4 | .section .data 5 | filename: .asciz "nums.txt" 6 | write_mode: .asciz "w" 7 | format_str: .asciz "%d\n" 8 | format_str_result: .asciz "Fibonacci Number: %d\n" 9 | 10 | .section .text 11 | 12 | print_num_to_file: 13 | push {lr} 14 | push {r0-r5} 15 | 16 | mov r5, r0 17 | 18 | // Open the file for writing 19 | ldr r0, =filename 20 | ldr r1, =write_mode 21 | bl fopen 22 | mov r4, r0 // Store the file pointer in r4 23 | 24 | // Check if fopen succeeded 25 | cmp r4, #0 26 | beq close_file 27 | 28 | // Write the number to the file 29 | mov r0, r4 30 | ldr r1, =format_str 31 | mov r2, r5 32 | bl fprintf 33 | 34 | // Close the file 35 | close_file: 36 | mov r0, r4 37 | bl fclose 38 | 39 | pop {r0-r5} 40 | pop {pc} 41 | 42 | fibonacci: 43 | push {lr} 44 | 45 | // Replace this with your code! Return value goes in r0 46 | mov r0, #42 47 | 48 | end_fib: 49 | pop {pc} 50 | 51 | main: 52 | push {r4-r7, lr} 53 | 54 | // Check if argument count (argc) is correct 55 | cmp r0, #2 // Expecting 2 arguments (program name and n) 56 | blt exit 57 | 58 | // Convert argument string to integer 59 | ldr r0, [r1, #4] // Load address of second argument (n value) 60 | bl atoi // Convert string to integer 61 | mov r4, r0 62 | 63 | // Calculate the nth Fibonacci number 64 | mov r0, r4 65 | bl fibonacci 66 | 67 | // Print fib result to our file 68 | bl print_num_to_file 69 | 70 | exit: 71 | // Exit 72 | mov r0, #0 73 | pop {r4-r7, pc} 74 | -------------------------------------------------------------------------------- /Fibonacci/run_fib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if an argument was provided 4 | if [ "$#" -ne 1 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | # Check if the argument is an integer 10 | if ! [[ $1 =~ ^[0-9]+$ ]]; then 11 | echo "Error: Argument must be an integer." 12 | exit 1 13 | fi 14 | 15 | python3 fib.py & 16 | 17 | # Check if the 'fib' executable exists in the current directory 18 | if [ ! -f "./fib" ]; then 19 | echo "Error: 'fib' executable not found in the current directory." 20 | exit 1 21 | fi 22 | 23 | # Run the 'fib' executable in a loop with a delay 24 | for (( i = 0; i <= $1; i++ )); do 25 | ./fib "$i" 26 | sleep 0.3 # Wait for 0.3 seconds 27 | done 28 | 29 | -------------------------------------------------------------------------------- /Fibonacci/spiral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurieWired/Assembly-Algorithms/70972190ae5455a3d9735c5c2deaa1f71e47bec2/Fibonacci/spiral.png -------------------------------------------------------------------------------- /GCD/euclid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurieWired/Assembly-Algorithms/70972190ae5455a3d9735c5c2deaa1f71e47bec2/GCD/euclid.png -------------------------------------------------------------------------------- /GCD/fillable_gcd.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi 3 | 4 | .section .data 5 | filename: .asciz "nums.txt" 6 | write_mode: .asciz "w" 7 | format_str: .asciz "%d\n" 8 | 9 | .section .text 10 | 11 | print_num_to_file: 12 | push {lr} 13 | push {r0-r5} 14 | 15 | mov r5, r0 16 | 17 | // Open the file for writing 18 | ldr r0, =filename 19 | ldr r1, =write_mode 20 | bl fopen 21 | mov r4, r0 // Store the file pointer in r4 22 | 23 | // Check if fopen succeeded 24 | cmp r4, #0 25 | beq close_file 26 | 27 | // Write the number to the file 28 | mov r0, r4 29 | ldr r1, =format_str 30 | mov r2, r5 31 | bl fprintf 32 | 33 | // Close the file 34 | close_file: 35 | mov r0, r4 36 | bl fclose 37 | 38 | pop {r0-r5} 39 | pop {pc} 40 | 41 | gcd: 42 | push {lr} 43 | 44 | // Replace this with your code! Return value goes in r0 45 | mov r0, #-1 46 | 47 | end_gcd: 48 | pop {pc} 49 | 50 | main: 51 | push {r4-r7, lr} 52 | 53 | // Check if argument count (argc) is correct 54 | cmp r0, #3 // Expecting 3 arguments (program name and two operands) 55 | blt exit 56 | 57 | // Convert argument strings to integers 58 | push {r1} 59 | ldr r0, [r1, #4] // Load address of second argument (first operand) 60 | bl atoi // Convert string to integer 61 | mov r4, r0 62 | pop {r1} 63 | 64 | push {r4} 65 | ldr r0, [r1, #8] // Load address of third argument (second operand) 66 | bl atoi // Convert string to integer 67 | mov r5, r0 68 | pop {r4} 69 | 70 | // Calculate the gcd of both operands 71 | mov r0, r4 72 | mov r1, r5 73 | bl gcd 74 | 75 | // Print gcd result to our file 76 | bl print_num_to_file 77 | 78 | exit: 79 | // Exit 80 | mov r0, #0 81 | pop {r4-r7, pc} 82 | 83 | .section .note.GNU-stack -------------------------------------------------------------------------------- /GCD/gcd.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from PIL import Image, ImageTk 3 | 4 | def read_gcd_from_file(label, canvas, circle, root): 5 | circle_radius = 50 # Should be the same as in main() 6 | 7 | try: 8 | with open("nums.txt", "r") as file: 9 | # Read the first line only 10 | current_number = file.readline().strip() 11 | label.config(text=current_number) 12 | 13 | # Update position of label and circle 14 | x = 150 # You can adjust this to change the initial position 15 | y = 250 # You can adjust this to change the initial position 16 | label.place(x=x, y=y, anchor="center") 17 | canvas.coords(circle, x - circle_radius, y - circle_radius, 18 | x + circle_radius, y + circle_radius) 19 | except Exception as e: 20 | print(f"Error reading file: {e}") 21 | label.config(text="Error") 22 | 23 | def main(): 24 | root = tk.Tk() 25 | root.title("GCD Calculator") 26 | 27 | # Get screen width and height 28 | screen_width = root.winfo_screenwidth() 29 | screen_height = root.winfo_screenheight() 30 | 31 | # Set the geometry for the window to full screen 32 | root.geometry(f"{screen_width}x{screen_height}+0+0") 33 | 34 | # Load and resize the background image 35 | bg_image_path = "euclid.png" 36 | bg_image = Image.open(bg_image_path) 37 | bg_image = bg_image.resize((screen_width, screen_height), Image.LANCZOS) 38 | bg_photo = ImageTk.PhotoImage(bg_image) 39 | 40 | # Create a canvas that fills the whole window and set the background image 41 | canvas = tk.Canvas(root, width=screen_width, height=screen_height) 42 | canvas.pack(fill="both", expand=True) 43 | canvas.create_image(0, 0, image=bg_photo, anchor="nw") 44 | 45 | # Create a canvas circle for the background of the number 46 | circle_radius = 50 47 | circle = canvas.create_oval( 48 | screen_width // 2 - circle_radius, 49 | screen_height // 2 - circle_radius, 50 | screen_width // 2 + circle_radius, 51 | screen_height // 2 + circle_radius, 52 | fill='white', 53 | outline='white' 54 | ) 55 | 56 | # Create a label for displaying the number 57 | gcd_label= tk.Label(root, text="", font=("Helvetica", 40), fg='black', bg='white') 58 | gcd_label.place(x=screen_width // 2, y=screen_height // 2, anchor="center") 59 | 60 | # Call the function to read the number from the file and update the label 61 | read_gcd_from_file(gcd_label, canvas, circle, root) 62 | 63 | root.mainloop() 64 | 65 | if __name__ == "__main__": 66 | main() 67 | -------------------------------------------------------------------------------- /GCD/gcd.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi 3 | 4 | .section .data 5 | filename: .asciz "nums.txt" 6 | write_mode: .asciz "w" 7 | format_str: .asciz "%d\n" 8 | 9 | .section .text 10 | 11 | print_num_to_file: 12 | push {lr} 13 | push {r0-r5} 14 | 15 | mov r5, r0 16 | 17 | // Open the file for writing 18 | ldr r0, =filename 19 | ldr r1, =write_mode 20 | bl fopen 21 | mov r4, r0 // Store the file pointer in r4 22 | 23 | // Check if fopen succeeded 24 | cmp r4, #0 25 | beq close_file 26 | 27 | // Write the number to the file 28 | mov r0, r4 29 | ldr r1, =format_str 30 | mov r2, r5 31 | bl fprintf 32 | 33 | // Close the file 34 | close_file: 35 | mov r0, r4 36 | bl fclose 37 | 38 | pop {r0-r5} 39 | pop {pc} 40 | 41 | gcd: 42 | push {lr} 43 | 44 | // Base case 45 | // if (b == 0) return a 46 | cmp r1, #0 47 | beq end_gcd 48 | 49 | // Recursive case 50 | // return gcd(b, a % b) 51 | 52 | // Compute a % b 53 | sdiv r2, r0, r1 54 | mul r3, r2, r1 55 | sub r4, r0, r3 // r4 now contains the modulus 56 | 57 | // Now compute gcd(b, a % b) 58 | mov r0, r1 59 | mov r1, r4 60 | bl gcd 61 | 62 | end_gcd: 63 | pop {pc} 64 | 65 | main: 66 | push {r4-r7, lr} 67 | 68 | // Check if argument count (argc) is correct 69 | cmp r0, #3 // Expecting 3 arguments (program name and two operands) 70 | blt exit 71 | 72 | // Convert argument strings to integers 73 | push {r1} 74 | ldr r0, [r1, #4] // Load address of second argument (first operand) 75 | bl atoi // Convert string to integer 76 | mov r4, r0 77 | pop {r1} 78 | 79 | push {r4} 80 | ldr r0, [r1, #8] // Load address of third argument (second operand) 81 | bl atoi // Convert string to integer 82 | mov r5, r0 83 | pop {r4} 84 | 85 | // Calculate the gcd of both operands 86 | mov r0, r4 87 | mov r1, r5 88 | bl gcd 89 | 90 | // Print gcd result to our file 91 | bl print_num_to_file 92 | 93 | exit: 94 | // Exit 95 | mov r0, #0 96 | pop {r4-r7, pc} 97 | 98 | .section .note.GNU-stack -------------------------------------------------------------------------------- /GCD/run_gcd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if two arguments were provided 4 | if [ "$#" -ne 2 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | # Check if both arguments are integers 10 | if ! [[ $1 =~ ^[0-9]+$ ]] || ! [[ $2 =~ ^[0-9]+$ ]]; then 11 | echo "Error: Both arguments must be integers." 12 | exit 1 13 | fi 14 | 15 | # Check if the 'gcd' executable exists in the current directory 16 | if [ ! -f "./gcd" ]; then 17 | echo "Error: 'gcd' executable not found in the current directory." 18 | exit 1 19 | fi 20 | 21 | # Run the 'gcd' executable with the provided arguments 22 | ./gcd "$1" "$2" 23 | 24 | # Call gcd.py to display the result 25 | python3 gcd.py "$1" "$2" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Assembly Algorithms :rocket: 2 | Welcome to the Assembly Algorithms code repository where we dive into the world of assembly to implement iconic computer science algorithms in pure assembly! :computer: 3 | 4 | ## What is this repository? :mag_right: 5 | 6 | This repository contains algorithms implemented in pure assembly language. It will be added to continuously to include more algorithms. It's designed to teach, inspire, and challenge programmers to understand and appreciate the power of assembly language - the closest form of communication we have to our underlying systems. 7 | 8 | ## Why learn assembly? :thinking: 9 | 10 | - **Speed:** Experience the enhanced performance of code that's just a step away from binary. 11 | - **Understanding:** Learn how higher-level constructs are built by controlling the CPU directly. 12 | - **Appreciation:** Gain a newfound respect for compilers and high-level languages. 13 | - **Fun:** There's a unique joy in making things work in assembly, and we're here to find it. 14 | 15 | ## Getting Started :runner: 16 | 17 | Here's how to get started: 18 | 19 | 1. **Clone this repository:** `git clone https://github.com/LaurieWired/Assembly-Algorithms.git` 20 | 2. **Pick an algorithm:** Browse the repository and choose an algorithm to sink your teeth into. 21 | 3. **Use the default code or fill in your own version:** If you want to write your own version, simply go to the `algorithm_fillable.s` file and add your own code. 22 | 4. **Generate the executable:** Assemble the algorithm file and create the executable. For ARMv7, use the following: 23 | ``` 24 | arm-linux-gnueabi-as algorithm.s -o algorithm.o # Update "algorithm" to the selected algorithm name 25 | arm-linux-gnueabi-gcc -static algorithm.o -o algorithm 26 | ``` 27 | 5. **Run the code:** Either run the executable directly or call `./run_algorithm.sh` to visualize the algorithm. 28 | 29 | 30 | ## Accompanying Videos :video_camera: 31 | If you want more explanations of the algorithm, follow the accompanying video explanation on YouTube! 32 | 33 | - **Fibonacci Sequence:** [Using recursion in assembly to compute the fibonacci sequence](https://youtu.be/rGg94EDHl6I) 34 | - **Euclidean Algorithm:** [Computing the Euclidean Algorithm in raw ARM Assembly](https://youtu.be/665rzOSSxWA) 35 | -------------------------------------------------------------------------------- /StackOverflow/overflow.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi, sleep 3 | 4 | .section .data 5 | format_str_depth: .asciz "Depth: %d\n" 6 | format_str_sp: .asciz "Stack pointer: %p\n" 7 | filename: .asciz "original_sp.txt" 8 | filename_latest_sp: .asciz "latest_sp.txt" 9 | write_mode: .asciz "w" 10 | format_str: .asciz "%p\n" 11 | 12 | .section .text 13 | 14 | print_original_sp_to_file: 15 | push {lr} 16 | push {r0-r5} 17 | 18 | // Open the file for writing 19 | ldr r0, =filename 20 | ldr r1, =write_mode 21 | bl fopen 22 | mov r4, r0 // Store the file pointer in r4 23 | 24 | // Check if fopen succeeded 25 | cmp r4, #0 26 | beq close_file 27 | 28 | // Write the number to the file 29 | mov r0, r4 30 | ldr r1, =format_str 31 | mov r2, sp 32 | bl fprintf 33 | 34 | // Close the file 35 | close_file: 36 | mov r0, r4 37 | bl fclose 38 | 39 | pop {r0-r5} 40 | pop {pc} 41 | 42 | print_latest_sp_to_file: 43 | push {lr} 44 | push {r0-r5} 45 | 46 | // Open the file for writing 47 | ldr r0, =filename_latest_sp 48 | ldr r1, =write_mode 49 | bl fopen 50 | mov r4, r0 // Store the file pointer in r4 51 | 52 | // Check if fopen succeeded 53 | cmp r4, #0 54 | beq close_file_latest 55 | 56 | // Write the number to the file 57 | mov r0, r4 58 | ldr r1, =format_str 59 | mov r2, sp 60 | bl fprintf 61 | 62 | // Close the second file 63 | close_file_latest: 64 | mov r0, r4 65 | bl fclose 66 | 67 | pop {r0-r5} 68 | pop {pc} 69 | 70 | recurse: 71 | push {lr} 72 | 73 | push {r0} // Saving the depth argument 74 | // Print depth to the console 75 | mov r1, r0 76 | ldr r0, =format_str_depth 77 | bl printf 78 | pop {r0} 79 | 80 | // Only print to the file every 1000 levels to help with perf 81 | // Check if depth is divisible by 1000 and print if so 82 | push {r0} // Saving the depth argument 83 | 84 | // Compute the modulus to see if there is remainder 85 | mov r1, #1000 86 | sdiv r2, r0, r1 87 | mul r3, r2, r1 88 | sub r4, r0, r3 89 | cmp r4, #0 90 | bne skip_sp_print // We only want to print every 1000 times so skip this one 91 | 92 | bl print_latest_sp_to_file 93 | 94 | skip_sp_print: 95 | // Print stack pointer to the console 96 | mov r1, sp 97 | ldr r0, =format_str_sp 98 | bl printf 99 | 100 | pop {r0} 101 | 102 | // Increase depth by 1 before recursing 103 | add r0, r0, #1 104 | bl recurse 105 | 106 | recurse_exit: 107 | pop {pc} 108 | 109 | main: 110 | push {r4-r7, lr} 111 | 112 | bl print_original_sp_to_file 113 | 114 | // Call recurse until we cause a stack overflow 115 | mov r0, #1 116 | bl recurse 117 | 118 | exit: 119 | // Exit 120 | mov r0, #0 121 | pop {r4-r7, pc} 122 | 123 | 124 | .section .note.GNU-stack 125 | 126 | -------------------------------------------------------------------------------- /StackOverflow/overflow_fillable.s: -------------------------------------------------------------------------------- 1 | .global main 2 | .extern fopen, fprintf, fclose, printf, atoi, sleep 3 | 4 | .section .data 5 | format_str_depth: .asciz "Depth: %d\n" 6 | format_str_sp: .asciz "Stack pointer: %p\n" 7 | filename: .asciz "original_sp.txt" 8 | filename_latest_sp: .asciz "latest_sp.txt" 9 | write_mode: .asciz "w" 10 | format_str: .asciz "%p\n" 11 | 12 | .section .text 13 | 14 | print_original_sp_to_file: 15 | push {lr} 16 | push {r0-r5} 17 | 18 | // Open the file for writing 19 | ldr r0, =filename 20 | ldr r1, =write_mode 21 | bl fopen 22 | mov r4, r0 // Store the file pointer in r4 23 | 24 | // Check if fopen succeeded 25 | cmp r4, #0 26 | beq close_file 27 | 28 | // Write the number to the file 29 | mov r0, r4 30 | ldr r1, =format_str 31 | mov r2, sp 32 | bl fprintf 33 | 34 | // Close the file 35 | close_file: 36 | mov r0, r4 37 | bl fclose 38 | 39 | pop {r0-r5} 40 | pop {pc} 41 | 42 | print_latest_sp_to_file: 43 | push {lr} 44 | push {r0-r5} 45 | 46 | // Open the file for writing 47 | ldr r0, =filename_latest_sp 48 | ldr r1, =write_mode 49 | bl fopen 50 | mov r4, r0 // Store the file pointer in r4 51 | 52 | // Check if fopen succeeded 53 | cmp r4, #0 54 | beq close_file_latest 55 | 56 | // Write the number to the file 57 | mov r0, r4 58 | ldr r1, =format_str 59 | mov r2, sp 60 | bl fprintf 61 | 62 | // Close the second file 63 | close_file_latest: 64 | mov r0, r4 65 | bl fclose 66 | 67 | pop {r0-r5} 68 | pop {pc} 69 | 70 | recurse: 71 | push {lr} 72 | 73 | push {r0} // Saving the depth argument 74 | // Print depth to the console 75 | mov r1, r0 76 | ldr r0, =format_str_depth 77 | bl printf 78 | pop {r0} 79 | 80 | // Only print to the file every 1000 levels to help with perf 81 | // Check if depth is divisible by 1000 and print if so 82 | push {r0} // Saving the depth argument 83 | 84 | // Compute the modulus to see if there is remainder 85 | mov r1, #1000 86 | sdiv r2, r0, r1 87 | mul r3, r2, r1 88 | sub r4, r0, r3 89 | cmp r4, #0 90 | bne skip_sp_print // We only want to print every 1000 times so skip this one 91 | 92 | bl print_latest_sp_to_file 93 | 94 | skip_sp_print: 95 | // Print stack pointer to the console 96 | mov r1, sp 97 | ldr r0, =format_str_sp 98 | bl printf 99 | 100 | pop {r0} 101 | 102 | // Increase depth by 1 before recursing 103 | 104 | // Your code goes here! 105 | 106 | recurse_exit: 107 | pop {pc} 108 | 109 | main: 110 | push {r4-r7, lr} 111 | 112 | bl print_original_sp_to_file 113 | 114 | // Call recurse until we cause a stack overflow 115 | mov r0, #1 116 | bl recurse 117 | 118 | exit: 119 | // Exit 120 | mov r0, #0 121 | pop {r4-r7, pc} 122 | 123 | 124 | .section .note.GNU-stack 125 | 126 | -------------------------------------------------------------------------------- /StackOverflow/run_overflow.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Remove old files 4 | rm -rf latest_sp.txt 5 | rm -rf original_sp.txt 6 | 7 | touch latest_sp.txt 8 | 9 | # Get the stack size limit 10 | stack_size_limit=$(ulimit -s) 11 | 12 | # Start the Python GUI in the background and detach it, passing the stack size limit as an argument 13 | nohup python3 show_overflow.py "$stack_size_limit" & 14 | nohup python3 show_stack.py "$stack_size_limit" & 15 | 16 | # Check if the 'overflow' executable exists in the current directory 17 | if [ ! -f "./overflow" ]; then 18 | echo "Error: 'overflow' executable not found in the current directory." 19 | exit 1 20 | fi 21 | 22 | # Give the Python scripts a little time to initialize the GUI 23 | sleep 2 24 | 25 | # Run the 'overflow' executable which will write to the stack pointer tracking files 26 | ./overflow 27 | 28 | -------------------------------------------------------------------------------- /StackOverflow/show_overflow.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import ttk 3 | import tkinter.font as font 4 | import threading 5 | import time 6 | import os 7 | import sys 8 | 9 | class FileWatcherGUI: 10 | def __init__(self, root, stack_limit): 11 | self.root = root 12 | self.stack_limit = int(stack_limit) # Convert stack limit to integer, in KB 13 | self.root.title("Stack Usage Visualizer") 14 | 15 | self.frame = ttk.Frame(self.root, padding="10") 16 | self.frame.pack(fill=tk.BOTH, expand=True) 17 | 18 | myFont = font.Font(size=15) 19 | 20 | self.label = ttk.Label(self.frame, text="Waiting for data...", font=myFont) 21 | self.label.pack() 22 | 23 | # Configure style for a red progress bar 24 | style = ttk.Style(self.root) 25 | style.theme_use('default') # Use default theme as a baseline for customization 26 | style.configure("Red.Vertical.TProgressbar", troughcolor='gray', background='red', thickness=30) 27 | 28 | # Initialize the progress bar with the custom style 29 | self.progress = ttk.Progressbar(self.frame, length=300, mode='determinate', 30 | orient='vertical', style="Red.Vertical.TProgressbar") 31 | self.progress.pack() 32 | self.progress['maximum'] = self.stack_limit # Set the stack limit as the maximum value 33 | 34 | # Read original SP value 35 | self.original_sp = self.read_original_sp() 36 | 37 | # Start the background thread 38 | self.stop_thread = False 39 | self.thread = threading.Thread(target=self.update_label) 40 | self.thread.start() 41 | 42 | # Ensure the thread stops when the GUI is closed 43 | self.root.protocol("WM_DELETE_WINDOW", self.on_closing) 44 | 45 | def read_original_sp(self): 46 | """Wait for original_sp.txt to exist and read the hex value.""" 47 | while not os.path.exists("original_sp.txt"): 48 | time.sleep(1) # Wait for the file to be created 49 | with open("original_sp.txt", "r") as file: 50 | return file.read().strip() # Read and return the hex value 51 | 52 | def update_label(self): 53 | """Background thread function to update the label and progress bar.""" 54 | while not self.stop_thread: 55 | try: 56 | with open("latest_sp.txt", "r") as file: 57 | latest_sp_hex = file.read().strip() 58 | if latest_sp_hex: 59 | latest_sp = int(latest_sp_hex, 16) 60 | original_sp = int(self.original_sp, 16) 61 | 62 | stack_usage_bytes = abs(original_sp - latest_sp) 63 | stack_usage_kb = stack_usage_bytes / 1024 64 | 65 | # Update the GUI with the new stack usage info 66 | self.label.config(text=f"Stack Limit: {self.stack_limit} KB\nStack Usage: {stack_usage_kb:.2f} KB") 67 | self.progress['value'] = stack_usage_kb # Update the progress bar 68 | except Exception as e: 69 | self.label.config(text=f"Error: {e}") 70 | time.sleep(1) 71 | 72 | def on_closing(self): 73 | """Handle the GUI closing event.""" 74 | self.stop_thread = True 75 | self.thread.join() 76 | self.root.destroy() 77 | 78 | def main(): 79 | if len(sys.argv) > 1: 80 | stack_limit = sys.argv[1] 81 | else: 82 | stack_limit = "Unknown" 83 | 84 | root = tk.Tk() 85 | app = FileWatcherGUI(root, stack_limit) 86 | root.mainloop() 87 | 88 | if __name__ == "__main__": 89 | main() 90 | 91 | -------------------------------------------------------------------------------- /StackOverflow/show_stack.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import ttk 3 | import tkinter.font as font 4 | import threading 5 | import time 6 | import os 7 | import sys 8 | 9 | class FileWatcherGUI: 10 | def __init__(self, root, stack_limit): 11 | self.root = root 12 | self.stack_limit = int(stack_limit) # Convert stack limit to integer, in KB 13 | self.root.title("Stack Pointer Visualizer") 14 | 15 | self.frame = ttk.Frame(self.root, padding="10") 16 | self.frame.pack(fill=tk.BOTH, expand=True) 17 | 18 | myFont = font.Font(size=15) 19 | 20 | self.label = ttk.Label(self.frame, text="Waiting for data...", font=myFont) 21 | self.label.pack() 22 | 23 | # Configure style for a red progress bar 24 | style = ttk.Style(self.root) 25 | style.theme_use('default') # Use default theme as a baseline for customization 26 | style.configure("Red.Vertical.TProgressbar", troughcolor='blue', background='gray', thickness=30) 27 | 28 | # Initialize the progress bar for current SP value 29 | self.progress_sp = ttk.Progressbar(self.frame, length=300, mode='determinate', 30 | orient='vertical', style="Red.Vertical.TProgressbar") 31 | self.progress_sp.pack() 32 | self.progress_sp['maximum'] = 100 # Use a percentage scale 33 | 34 | # Read original SP value 35 | self.original_sp = self.read_original_sp() 36 | 37 | # Start the background thread 38 | self.stop_thread = False 39 | self.thread = threading.Thread(target=self.update_label) 40 | self.thread.start() 41 | 42 | # Ensure the thread stops when the GUI is closed 43 | self.root.protocol("WM_DELETE_WINDOW", self.on_closing) 44 | 45 | def read_original_sp(self): 46 | """Wait for original_sp.txt to exist and read the hex value.""" 47 | while not os.path.exists("original_sp.txt"): 48 | time.sleep(1) # Wait for the file to be created 49 | with open("original_sp.txt", "r") as file: 50 | return file.read().strip() # Read and return the hex value 51 | 52 | def update_label(self): 53 | """Background thread function to update the label and progress bar.""" 54 | while not self.stop_thread: 55 | try: 56 | with open("latest_sp.txt", "r") as file: 57 | latest_sp_hex = file.read().strip() 58 | if latest_sp_hex: 59 | latest_sp = int(latest_sp_hex, 16) 60 | original_sp = int(self.original_sp, 16) 61 | 62 | # Calculate minimum stack pointer value 63 | min_sp_value = original_sp - (self.stack_limit * 1024) 64 | min_sp_value_hex = hex(min_sp_value) 65 | 66 | # Normalize the current SP position for the progress bar 67 | sp_range = original_sp - min_sp_value 68 | current_sp_position = latest_sp - min_sp_value 69 | if sp_range > 0: 70 | sp_percentage = (current_sp_position / sp_range) * 100 71 | else: 72 | sp_percentage = 0 73 | self.progress_sp['value'] = sp_percentage 74 | 75 | # Update the GUI with the new stack pointer info 76 | self.label.config(text=f"Stack Pointer: {latest_sp_hex}\nMin Stack: {min_sp_value_hex}") 77 | except Exception as e: 78 | self.label.config(text=f"Error: {e}") 79 | time.sleep(1) 80 | 81 | def on_closing(self): 82 | """Handle the GUI closing event.""" 83 | self.stop_thread = True 84 | self.thread.join() 85 | self.root.destroy() 86 | 87 | def main(): 88 | if len(sys.argv) > 1: 89 | stack_limit = sys.argv[1] 90 | else: 91 | stack_limit = "Unknown" 92 | 93 | root = tk.Tk() 94 | app = FileWatcherGUI(root, stack_limit) 95 | root.mainloop() 96 | 97 | if __name__ == "__main__": 98 | main() 99 | 100 | --------------------------------------------------------------------------------