🗂
Brainfuck interpreter in x86_64 assembly
x86_64アセンブリで書かれた、単純なbrainfuck interpreterです。
FreeBSDのシステムコールを使っています。システムコールの仕方、コマンドライン引数の取得の仕方にテンプレとしてどうぞ。
bf.s
; Brainfuck interpreter
; FreeBSD x86_64
; Pure syscall
; Intel syntax (NASM)
; build:
; nasm -f elf64 bf.s
; ld bf.o -o bf
BITS 64
GLOBAL _start
%define SYS_EXIT 1
%define SYS_READ 3
%define SYS_WRITE 4
%define SYS_OPEN 5
%define SYS_CLOSE 6
SECTION .data
usage: db "Usage: bf <file>",10
usage_len equ $-usage
SECTION .bss
tape resb 65536
prog_buf resb 1048576
SECTION .text
_start:
; FreeBSD x86_64: rdi = スタックポインタ (argc, argv[0], argv[1], ...)
; rsp は rdi と一致することもあれば 8 バイトずれることもあるため rdi を使う
mov r8, rdi ; r8 = &argc (スタック先頭)
mov eax, [r8] ; argc
cmp eax, 2
jge open_file
mov rax, SYS_WRITE
mov rdi, 2 ; stderr
mov rsi, usage
mov rdx, usage_len
syscall
mov rax, SYS_EXIT
mov rdi, 1
syscall
open_file:
mov rdi, [r8+16] ; argv[1] (r8+8=argv[0], r8+16=argv[1])
mov rax, SYS_OPEN
xor rsi, rsi ; O_RDONLY
xor rdx, rdx ; mode=0
syscall
jc exit_error ; FreeBSD: CF=1 はエラー
mov r12, rax ; fd
; read whole file
mov rax, SYS_READ
mov rdi, r12
mov rsi, prog_buf
mov rdx, 1048576
syscall
mov r13, rax ; program length
mov rax, SYS_CLOSE
mov rdi, r12
syscall
; init
xor r14, r14 ; instruction pointer
xor r15, r15 ; tape pointer
main_loop:
cmp r14, r13
jge exit
mov al, [prog_buf + r14]
cmp al, '>'
je op_inc_ptr
cmp al, '<'
je op_dec_ptr
cmp al, '+'
je op_inc_val
cmp al, '-'
je op_dec_val
cmp al, '.'
je op_output
cmp al, ','
je op_input
cmp al, '['
je op_loop_start
cmp al, ']'
je op_loop_end
next:
inc r14
jmp main_loop
; ----- operations -----
op_inc_ptr:
inc r15
jmp next
op_dec_ptr:
dec r15
jmp next
op_inc_val:
inc byte [tape + r15]
jmp next
op_dec_val:
dec byte [tape + r15]
jmp next
op_output:
mov rax, SYS_WRITE
mov rdi, 1
lea rsi, [tape + r15]
mov rdx, 1
syscall
jmp next
op_input:
mov rax, SYS_READ
mov rdi, 0
lea rsi, [tape + r15]
mov rdx, 1
syscall
cmp rax, 0
jle exit ; EOF またはエラー → 終了
jmp next
; ----- loops -----
op_loop_start:
cmp byte [tape + r15], 0
jne next
mov rcx, 1
.find_end:
inc r14
cmp r14, r13
jge exit
mov al, [prog_buf + r14]
cmp al, '['
je .inc_depth
cmp al, ']'
je .dec_depth
jmp .find_end
.inc_depth:
inc rcx
jmp .find_end
.dec_depth:
dec rcx
cmp rcx, 0
jne .find_end
jmp next
op_loop_end:
cmp byte [tape + r15], 0
je next
mov rcx, 1
.find_start:
cmp r14, 0
jle exit
dec r14
mov al, [prog_buf + r14]
cmp al, ']'
je .inc_depth2
cmp al, '['
je .dec_depth2
jmp .find_start
.inc_depth2:
inc rcx
jmp .find_start
.dec_depth2:
dec rcx
cmp rcx, 0
jne .find_start
jmp next
exit_error:
mov rax, SYS_EXIT
mov rdi, 1
syscall
exit:
mov rax, SYS_EXIT
xor rdi, rdi
syscall
Discussion