From ea84361ca8770439843bec13e0f5e0e60ba06969 Mon Sep 17 00:00:00 2001 From: cat Date: Sat, 21 Jun 2025 16:29:23 +0300 Subject: [PATCH] Adding everything --- .gitignore | 2 + compile.sh | 7 ++ debug.sh | 4 ++ helper.s | 131 +++++++++++++++++++++++++++++++++ main.s | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ test.txt | 1 + 6 files changed, 352 insertions(+) create mode 100644 .gitignore create mode 100755 compile.sh create mode 100755 debug.sh create mode 100644 helper.s create mode 100644 main.s create mode 100644 test.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14e8117 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +program +program.o diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..9d88f07 --- /dev/null +++ b/compile.sh @@ -0,0 +1,7 @@ +#!/bin/bash +as *.s -o program.o +# ld program.o -g -o program debugging +# ld program.o -N -s --strip-all --gc-sections -o program smallest +ld program.o -N -o program +strip program +echo "size =" $(wc -c program) "octets" diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..4c1a3f1 --- /dev/null +++ b/debug.sh @@ -0,0 +1,4 @@ +#!/bin/bash +as *.s -g -o program.o +ld program.o -g -o program +gdb --args ./program $@ diff --git a/helper.s b/helper.s new file mode 100644 index 0000000..84ebb93 --- /dev/null +++ b/helper.s @@ -0,0 +1,131 @@ +.intel_syntax noprefix +.data +error_msg_closefd: .ascii "Cannot close STD IO!\n\0" +error_msg_openfd_noexist: .ascii "The file does not exist or can't be opened!\n\0" +code_max_size: .quad 65536 +max_size: .quad 16384 + +.text + +# =================== +# Memory Allocs +# =================== +# rdi = address +# rsi = size +clear_heap_block: + xor rcx, rcx +clear_heap_block_loop: + mov byte ptr [rdi+rcx], 0 + inc rcx + cmp rcx, rsi + jle clear_heap_block_loop + ret + +# rdi = size in octets +brk_alloc: + push rbx + push r12 + inc rdi # so you get all of the requested space + mov rbx, rdi + + mov rax, 12 + xor rdi, rdi + syscall + + mov rdi, rax # To push brk + add rdi, rbx + mov r12, rax # To return + + # Pushed + mov rax, 12 + syscall + + mov rax, r12 + + # Gotta return + pop r12 + pop rbx + ret + + +# =================== +# File I/O +# =================== +# rdi = FD +# rsi = char* +# rdx = size +read: + push r11 # read uses r11 + xor rax, rax + syscall + pop r11 + ret + +# rdi = FD +# rsi = char* +write: + push r15 + mov r15, rdi + mov rdi, rsi # no need to touch rsi + call count + + mov rdx, rax # Lenght + mov rax, 1 + mov rdi, r15 + + syscall + pop r15 + ret + +# rdi = String to count +count: + mov rax, rdi +count_loop: + mov r8b, [rax] + inc rax + cmp r8b, 0 + jnz count_loop + dec rax + sub rax, rdi + ret + +# =================== +# File Handling +# =================== +# rdi = Path +open_fd: + mov rax, 2 + xor rsi, rsi # RO + mov rdx, 644 + syscall + cmp rax, 0 + jl error_out_open + ret + +# rdi = FD +close_fd: + cmp rdi, 0 + je error_out_close + mov rax, 3 + syscall + ret + +# =================== +# Exit & Errors +# =================== +# rdi = Exit code +exit: + mov rax, 60 + syscall + +error_out_close: + mov rdi, 1 + mov rsi, offset error_msg_closefd + call write + call exit + +error_out_open: + mov rdi, 1 + mov rsi, offset error_msg_openfd_noexist + call write + call exit diff --git a/main.s b/main.s new file mode 100644 index 0000000..e425782 --- /dev/null +++ b/main.s @@ -0,0 +1,207 @@ +.intel_syntax noprefix +.global _start + +.data +welcome: .ascii "Welcome to Brainfuck by cat, written in ASM(GNU)!\nMax char: 65536(incl LF)!\nAllocating memory...\n\0" +msg2: .ascii "Clearing buffer...\n\0" +msg3: .ascii "Reading code...\n\0" +msg4: .ascii "Interpreting...\n\0" +error_msg_no_path: .ascii "You must specify a path as first argument!!\nAborting!\n\0" + +.text +_start: + mov rdi, 1 + mov rsi, offset welcome + call write + + # Is file specified? + cmp qword ptr [rsp], 1 + jle error_no_path + + mov rdi, [rsp+16] # rsp is argc, rsp+8 is argv[0] + call open_fd + mov rbx, rax # FD + + # Allocate memory + mov rdi, code_max_size + call brk_alloc + mov r12, rax # Code heap + + mov rdi, max_size + call brk_alloc + mov r13, rax # Text buffer + + mov rdi, max_size + call brk_alloc + mov r14, rax # Cells + + mov rdi, 1 + mov rsi, offset msg2 + call write + + # Clear the space + mov rdi, r12 + mov rsi, code_max_size + call clear_heap_block + + mov rdi, r13 + mov rsi, max_size + call clear_heap_block + + mov rdi, r14 + mov rsi, max_size + call clear_heap_block + + mov rdi, 1 + mov rsi, offset msg3 + call write + + # Read from file + mov rdi, rbx + mov rsi, r12 + mov rdx, code_max_size + call read + + mov rdi, 1 + mov rsi, offset msg4 + call write + # Execution + call process_commands + + # Writing result + mov rdi, 1 + mov rsi, r13 + call write + + # Exiting procedures + mov rdi, rbx + call close_fd + + xor rdi, rdi + call exit + +error_no_path: + mov rdi, 1 + mov rsi, offset error_msg_no_path + call write + + mov rdi, 1 + call exit + +# r10 text pointer +# r11 code pointer +# r12 code +# r13 text +# r14 cell +# r15 cell pointer +process_commands: + xor r11, r11 + xor r15, r15 + mov r10, r13 +process_loop: + mov r8b, [r12+r11] # Get char + call process_symbol + inc r11 + cmp r8b, 0 + jne process_loop + ret + +# r8b = char +process_symbol: + cmp r8b, 43 # + + je process_inc + + cmp r8b, 45 # - + je process_dec + + cmp r8b, 60 # < + je process_back + + cmp r8b, 62 # > + je process_forw + + cmp r8b, 46 # . + je process_prnt + + cmp r8b, 44 # , + je process_inpt + + cmp r8b, 91 # [ + je process_loop_start + + cmp r8b, 93 # ] + je process_loop_end + + ret + +# Ret's here return to process_loop not process_symbol due to Jcc +process_inc: + inc byte ptr [r14+r15] + ret + +process_dec: + dec byte ptr [r14+r15] + ret + +# you can't go below or above allocated memory +process_forw: + cmp r15, max_size + je 1f + inc r15 +1: + ret + +process_back: + cmp r15, 0 + je 1f + dec r15 +1: + ret + +process_prnt: + mov r9b, [r14+r15] + mov byte ptr [r10], r9b + inc r10 + ret + +process_inpt: + mov rdi, r14 + add rdi, r15 + + mov rsi, rdi # char* + xor rdi, rdi # fd + mov rdx, 1 # size + call read + ret + +# In stack it is +# A = Address to loop back +# C = Cell to check +# AC AC AC AC AC AC AC <- pop here +process_loop_start: + pop rdi + push r11 # Address to loopback + push r15 # Cell to check + push rdi + ret + +process_loop_end: + # Gotta get ret value + pop rsi + pop rdi # Cell + pop rax # Address + + # if cell is 0 we are done with loop + cmp byte ptr [r14+rdi], 0 + je 1f + mov r11, rax + + # Make sure stack isn't caught on fire + push rax + push rdi + push rsi + ret +1: + push rsi + ret # Discard + diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..cd729e8 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +,+.......