Compare commits
3 Commits
244fe869e5
...
d59a5c8b39
Author | SHA1 | Date | |
---|---|---|---|
d59a5c8b39 | |||
d3cb608a55 | |||
ea84361ca8 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
bf-cat
|
||||
bf-cat.o
|
@@ -1,3 +1,9 @@
|
||||
# brainfuck-on-asm
|
||||
|
||||
My own brainfuck interpreter written in pure assembly and agony
|
||||
My own brainfuck interpreter written in pure assembly and agony.
|
||||
|
||||
# Compile
|
||||
You will need GAS(or as)! Just run ``compile.sh`` then voila!
|
||||
|
||||
# Running
|
||||
``./bf-cat path/to/brainfuck-script``
|
||||
|
5
compile.sh
Executable file
5
compile.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
as *.s -o bf-cat.o
|
||||
ld bf-cat.o -N -o bf-cat
|
||||
strip bf-cat
|
||||
echo "size =" $(wc -c bf-cat) "octets"
|
4
debug.sh
Executable file
4
debug.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
as *.s -g -o bf-cat.o
|
||||
ld bf-cat.o -g -o bf-cat
|
||||
gdb --args ./bf-cat $@
|
131
helper.s
Normal file
131
helper.s
Normal file
@@ -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
|
207
main.s
Normal file
207
main.s
Normal file
@@ -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
|
||||
|
Reference in New Issue
Block a user