Compare commits

...

3 commits

Author SHA1 Message Date
f5bebc56b8 Add a testsuite using beef bf interpreter 2019-01-05 22:44:30 +01:00
6ab1331032 Deleted -e option and bf interpreter capabilities 2019-01-05 22:44:05 +01:00
a9ac2eeff9 Enhancement of elf generation
Now addresses are absolutre from the elf code start => JIT do not
work anymore
2019-01-05 22:32:12 +01:00
7 changed files with 180 additions and 119 deletions

260
bfc.asm
View file

@ -1,4 +1,4 @@
; bfc : a brainfuck compiler & interpreter
; bfc : a brainfuck compiler
; Copyright (C) 2018 Weber Yann
;
; This program is free software; you can redistribute it and/or modify
@ -14,14 +14,13 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
; A brainfuck compiler & interpreter :
; A brainfuck compiler :
; Build : nasm -felf64 bfc.asm && ld -s -melf_x86_64 bfc.o -o bfc
;
; ./bfc [-h] [-e [-o a.out]] FILE.bf
; ./bfc [-h] [-o a.out] FILE.bf
; Options :
; -h print usage and exit
; -e tell bfc to produce a elf file
; -o with -e indicate the file to create
; -o indicate the file to create default is a.out
; FILE.bf the brainfuck source file to compile
[bits 64]
%use smartalign
@ -34,22 +33,33 @@ ALIGNMODE k8
%define MAP_INC_MASK 0x0FFF
%define BFMEM_INIT_SZ MAP_INC_SIZE
%define ELF_CODE_OFFSET 0x00400080
section .data
bf_start_head:
push 0x00400085
;dw 0x6885004000
bf_start_head_sz: equ $ - bf_start_head
bf_start:
jmp .start
.mremap: ; rbx is resize size
cmp rbx, MAP_INC_SIZE
jg .remap_cont
xor rbx, rbx
.remap_cont:
xor rbx, MAP_INC_MASK
add rbx, MAP_INC_SIZE
add r14, rbx
.mremap:
; Resize the mmap
; rbx is resize min size
; rdi is map ptr offset
; r14 is map_len
; r15 is map_addr
; Returns :
; r15 new map_addr
; r14 new map_len
; rdi map ptr offset
; rsi map ptr
push rdi
; set min resize
xor rdx, rdx
.loop_min_remap:
add rdx, MAP_INC_SIZE
cmp rdx, rbx
jl .loop_min_remap
add r14, rdx ; newlen
mov rax, 0x19 ; mremap
mov rdi, r15 ; addr
mov rsi, r14 ; oldlen
@ -61,6 +71,10 @@ section .data
cmp rax, 0
jle .erremap
mov r15, rax
; restore rsi & rdi
pop rdi
mov rsi, r15
add rsi, rdi
ret
.erremap:
mov rax, 0x3c
@ -68,23 +82,55 @@ section .data
syscall
align 8
.lbl_incresize: equ $ - bf_start
.incresize: ; rbx is resize size
.incresize:
; Resize the map on ptr increment
; rbx is increment count
; rdi is map ptr offset
; r14 is map_len
; r15 is map_addr
call .mremap
ret
align 8
.lbl_decresize: equ $ - bf_start
.decresize: ; rbx is decrement
push rsi
push r14
.decresize:
; Resize the map on ptr decrement
; rbx is decrement count
; rdi is map ptr offset
; r14 is map_len
; r15 is map_addr
; Note : data has to be shifted
push r14 ; old map len
call .incresize
pop rcx ; old size
; shift datas
pop rcx ; old len
mov rbx, r14 ; new_len
push rsi
push rdi
mov rsi, r15
mov rdi, rsi
inc rdi
.decresize_cpy:
add rsi, rcx ; add old_len to map_ptr
add rdi, rbx ; add new_len to map_ptr
sub rbx, rcx ; new_len - old_len : resize
std ; set DF to dec rsi & rdi
.decresize_shift:
movsb
loop .decresize_cpy
mov byte [r15], 0
loop .decresize_shift
; set first map bytes to 0
mov rdi, r15
add rdi, rbx
dec rdi
mov rcx, rbx
.decresize_zeros:
mov byte [rdi], 0x0
dec rdi
loop .decresize_zeros
pop rdi
pop rsi
; update map_ptr & offset given the shift
add rdi, rbx
add rsi, rbx
ret
.errmap:
mov rax, 0x3c
@ -103,67 +149,74 @@ section .data
syscall
cmp rax, 0
jle .errmap
mov r15, rax
; Sets BF runtime :
; r14 is map len
mov r15, rax ; r15 is map addr
mov rdi, (BFMEM_INIT_SZ / 2) ; rdi is ptr idx
mov rsi, r15
add rsi, (BFMEM_INIT_SZ / 2) ; BF ptr
add rsi, rdi ; rsi is bf ptr
align 8
bf_start_sz: equ $ - bf_start
; In piece of code call jump is achieved by adding
; an offset to the JIT map base addr
; this base address has to be on top of the stack
; when executing this small piece of code
;
; the first instruction has to be a mov of a byte
; in a register. This operation will be updated to
; "pass" a parameter
; In piece of code the first instruction has to be a mov of
; a quadword in a register. This operation will be updated
; to "pass" a parameter
; rsi is map_ptr
; rdi is map ptr offset
; r14 is map_len
; r15 is map_addr
bf_decptr:
; dec map ptr
; rbx is dec count
mov rbx, strict qword 0x1
push rbx
cmp rsi, rbx
cmp rdi, rbx
jge .end
mov rax, [rsp+8]
add rax, bf_start.lbl_decresize
mov rax, ELF_CODE_OFFSET + bf_start.lbl_decresize
call rax
;call (ELF_CODE_OFFSET + bf_start.lbl_decresize)
.end:
pop rbx
sub rsi, rbx
sub rdi, rbx
bf_decptr_sz: equ $ - bf_decptr
bf_incptr:
mov rbx, strict qword 0x1
push rbx
mov rax, rsi
sub rax, r15
cmp rax, r14
jl .end
mov rax, [rsp+8]
add rax, bf_start.lbl_incresize
add rbx, rdi
cmp rdi, r14
jge .end
mov rbx, [rsp]
mov rax, ELF_CODE_OFFSET + bf_start.lbl_incresize
call rax
;call (ELF_CODE_OFFSET + bf_start.lbl_incresize)
.end:
pop rbx
add rsi, rbx
add rdi, rbx
bf_incptr_sz: equ $ - bf_incptr
bf_incval:
mov rbx, strict qword 0x1
xor rax, rax
mov al,[rsi]
add rax, rbx
add al, bl
mov [rsi], al
bf_incval_sz: equ $ - bf_incval
bf_decval:
mov rbx, strict qword 0x1
xor rax, rax
mov al, [rsi]
sub rax, rbx
sub al, bl
mov [rsi], al
bf_decval_sz: equ $ - bf_decval
bf_readval:
mov rdx, strict qword 0x1
push rdi
push rsi
xor rax, rax ; read
xor rdi, rdi ; stdin
@ -173,22 +226,28 @@ section .data
mov byte [rsi], 0
.end:
pop rsi
pop rdi
bf_readval_sz: equ $ - bf_readval
bf_writeval:
mov rdx, strict qword 0x1
mov rcx, strict qword 0x1
push rdi
push rsi
xor rax, rax ; write
inc rax
mov rdi, rax ; stdout
syscall
.loop_write:
push rcx
mov rax, 1 ; write
mov rdi, rax ; stdout
mov rsi, [rsp+8]
mov rdx, 1 ; 1 chr
syscall
pop rcx
loop .loop_write
pop rsi
pop rdi
bf_writeval_sz: equ $ - bf_writeval
bf_loopstart:
mov rbx, strict qword 0x1
add rbx, [rsp]
xor rdx, rdx
mov dl, [rsi]
cmp dl, 0
jnz .end
@ -198,8 +257,6 @@ section .data
bf_loopend:
mov rbx, strict qword 0x1
add rbx, [rsp]
xor rdx, rdx
mov dl, [rsi]
cmp dl, 0
jz .end
@ -265,7 +322,7 @@ section .data
chr_list : db ": ", 0xA, 0x0
read_error: db "Error reading file "
read_error_sz: equ $ - read_error
usage_err: db "Usage : [-e [-o a.out]] FILE.BF"
usage_err: db "Usage : [-o a.out] FILE.BF"
usage_err_sz: equ $ - usage_err
open_err: db "Error opening file", 0xa
open_err_sz: equ $ - open_err
@ -276,9 +333,9 @@ _start:
; using heap to store arguments
%define bf_source [r13]
%define elf_file [r13+0x8]
%define elf_out [r13+0x11]
%define heap_size 0x12
%define heap_size 0x10
;heap init
mov rax, 0xc
xor rdi, rdi
syscall
@ -288,12 +345,15 @@ _start:
mov rax, 0xc
syscall
mov rax, default_output
mov elf_file, rax
;argument parsing
mov rcx, [rsp] ; argc
cmp rcx, 2
jl .badarg
je .init_1arg
cmp rcx, 5
;je .init_1arg
cmp rcx, 4
jg .badarg
mov rsi, rsp
@ -312,8 +372,6 @@ _start:
mov al, [rdi+1]
cmp al, 0x68 ; '-h'
je .badarg
cmp al, 0x65 ; '-e'
je .elfout_arg
cmp al, 0x6f ; '-o'
jne .badarg
@ -327,20 +385,6 @@ _start:
loop .argloop
jmp .init
.elfout_arg:
mov al, 0x1
mov elf_out, al
mov rax, elf_file
test rax, rax
jz .default_out
.elfout_arg_end:
loop .argloop
jmp .init
.default_out:
mov rax, default_output
mov elf_file, rax
jmp .elfout_arg_end
.filearg:
mov rax, bf_source
cmp rax, 0
@ -348,11 +392,7 @@ _start:
jnz .badarg ; file allready given
mov bf_source, rdi
loop .argloop
jmp .init
.init_1arg:
mov rax, [rsp+16]
mov bf_source, rax
jmp .init ; useless
.init:
; code map init
; rsi map size
@ -381,29 +421,8 @@ _start:
mov rax, 0x3 ; close
syscall
mov al, elf_out
test al, al
jnz .write_elf
.code_jmp:
; restore heap
mov rax, 0xc
mov rdi, r13
syscall
; set code map perm
mov rax, 0xA ; mprotect
mov rdi, r15
mov rsi, r14
mov rdx, 0x4 | 0x1 ; PROT_EXEC | PROT_READ
syscall
push r15
jmp r15 ; end... jumping in bf code map
.write_elf: ; writing elf file
; writing elf file
mov rax, [rsp] ; map len
add rax, bf_start_head_sz
mov [elf_section_text_sz], rax
add rax, elf_head_sz ; elf head + map_ptr
mov [elf_head + 0x60], rax
@ -439,12 +458,6 @@ _start:
mov rdx, elf_head_sz
syscall
mov rax, 1
mov rdi, [rsp]
mov rsi, bf_start_head
mov rdx, bf_start_head_sz
syscall
mov rax, 1
mov rdi, [rsp]
mov rsi, r15 ; map_addr
@ -769,15 +782,24 @@ compile_bf:
push rdx
call code_cpy
mov map_ptr, rax ; rax is map_ptr
pop rdx
sub rax, rdx
add rax, 2 ;arg addr in code map
mov rdi, rax
pop rdx ; bf_loopend_sz
lea rdi, [rax + 2]
sub rdi, rdx ; arg addr for loop_end : map_ptr - loopend_sz
pop rbx ; loop_start code offset
mov [rax], rbx ; loop end jump to start
lea rax, [rbx+ELF_CODE_OFFSET] ; jmp to loop_start in loop_end
mov [rdi], rax
.br1:
mov rax, map_ptr
sub rax, r15 ; loop end offset in map
add rbx, r15 ; loop start addr
mov [rbx+2], rax ; start jump to end
sub rax, r15 ; map_ptr - map_addr : map_offset of loop_end nxt instr
lea rdi, [rbx + r15 + 2] ; arg addr for loop_start in map
lea rax, [rax + ELF_CODE_OFFSET]
.br2:
mov [rdi], rax
.br3:
jmp .nxtinstr
.callcpy:

33
runtests.sh Executable file
View file

@ -0,0 +1,33 @@
#!/bin/sh
bfc="./bfc"
beef="beef"
make || exit 1
for bftest in tests/*.bf
do
for input in tests/*.in
do
beefres=$(tempfile)
bfcelf=$(tempfile)
bfcelfres=$(tempfile)
$beef -i $input $bftest > $beefres
$bfc -o $bfcelf $bftest 2>/dev/null
chmod +x $bfcelf
$bfcelf < $input > $bfcelfres
diff=$(diff $bfcelfres $beefres)
if [ -n "$diff" ]
then
echo "========"
echo "Error : $bftest on $input differs between bfc and beef"
diff $bfcelfres $beefres
hexdump -C $bfcres
hexdump -C $beefres
echo "========"
fi
echo "$bftest $input [OK]"
rm $beefres $bfcres $bfcelf $bfcelfres
done
done

1
tests/echo.bf Normal file
View file

@ -0,0 +1 @@
+[,[.>]<]

2
tests/hello.in Normal file
View file

@ -0,0 +1,2 @@
Hello world !

1
tests/helloworld.bf Normal file
View file

@ -0,0 +1 @@
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

1
tests/reverse.bf Normal file
View file

@ -0,0 +1 @@
+[<,]# >[>]<-<[<]#>[.>]

1
tests/rot13.bf Normal file
View file

@ -0,0 +1 @@
>++++++++[>+++++++++++[<<+>>-]<-]<-.++++++++++++++++++++++++..+++++.>++++++++++++[>+++++++[<<->>-]<-]<.>++++++++[>+++++++++++[<<+>>-]<-]<-.--------..+++++.>++++++++++++[>+++++++[<<->>-]<-]<.+.-.++++++++++++++++++++++++++.++++++++++.>+++[>+++++++++++++++++++[<<->>-]<-]<-.