├── asm ├── add1.asm ├── sub1.asm ├── ret.asm ├── deref_add.asm ├── deref_sub.asm ├── compare_and_jump.asm ├── jmp.asm ├── set.asm ├── print_linux.asm └── print_osx.asm ├── scripts ├── test_pointers.fck ├── hello.fck ├── nobranch.fck ├── slow.fck ├── helloworld.fck ├── fibonacci.fck ├── helloworld_commented_execution.fck └── mandelbrot.b ├── .gitignore ├── lib ├── gettime.h ├── interpreter.h ├── compiler.h ├── utils │ ├── stack.h │ └── stack.c ├── gettime.c ├── interpreter.c ├── dbg.h └── compiler.c ├── Dockerfile ├── possible-extensions.md ├── Makefile ├── LICENSE ├── brain.c └── README.md /asm/add1.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | add rdx, 1 4 | -------------------------------------------------------------------------------- /asm/sub1.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | sub rdx, 1 4 | -------------------------------------------------------------------------------- /scripts/test_pointers.fck: -------------------------------------------------------------------------------- 1 | ++--<<>>+-+-><+++++ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dSYM 2 | *.o 3 | *.bin 4 | .DS_Store 5 | tags 6 | -------------------------------------------------------------------------------- /asm/ret.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | ; allows a clean return to the C code 3 | ret 4 | -------------------------------------------------------------------------------- /asm/deref_add.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | ; '+' brainfuck instruction 3 | add byte [rdx], 1 4 | -------------------------------------------------------------------------------- /asm/deref_sub.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | ; '-' brainfuck instruction 3 | sub byte [rdx], 1 4 | -------------------------------------------------------------------------------- /scripts/hello.fck: -------------------------------------------------------------------------------- 1 | ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++. 2 | -------------------------------------------------------------------------------- /lib/gettime.h: -------------------------------------------------------------------------------- 1 | #ifndef _gettime_h_ 2 | #define _gettime_h 3 | double get_time(); 4 | #endif 5 | -------------------------------------------------------------------------------- /scripts/nobranch.fck: -------------------------------------------------------------------------------- 1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+.++. 2 | -------------------------------------------------------------------------------- /asm/compare_and_jump.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | ; used for the ']' brainfuck instruction 4 | cmp byte [rdx], 0 5 | jne -0x10 6 | -------------------------------------------------------------------------------- /asm/jmp.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | db 'prout' 4 | yolo: 5 | db 'abaaaaaaaaaaaaaaaa' 6 | 7 | mov al, [rdx] 8 | test eax,eax 9 | jnz yolo 10 | -------------------------------------------------------------------------------- /asm/set.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | ; used for setting the address of the playground 3 | ; 0xdeadbeefabad1dea is filled by the compiler 4 | mov rdx, 0xdeadbeefabad1dea 5 | -------------------------------------------------------------------------------- /scripts/slow.fck: -------------------------------------------------------------------------------- 1 | >+>+>+>+>++<[>[<+++>->>>>>>+>+>+>+>++<[>[<+++>->>>>>>+>+>+>+>++<[>[<+++>->>>>>>+>+>+>+>++<[>[<+++>->>>>>+++[->+++++<]>[-]<<<<<<]<<]>[-]<<<<<]<<]>[-]<<<<<]<<]>[-]<<<<<]<<]>. -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian 2 | 3 | RUN apt-get update && apt-get install -y build-essential libc6 strace 4 | 5 | WORKDIR /var/src/jit 6 | ADD . . 7 | 8 | ENTRYPOINT make clean && make && ./brain scripts/helloworld.fck 9 | 10 | -------------------------------------------------------------------------------- /lib/interpreter.h: -------------------------------------------------------------------------------- 1 | #ifndef _interpreter_h_ 2 | #define _interpreter_h_ 3 | 4 | // Will fetch one instruction at the time and execute it 5 | void interpreter_main_loop(unsigned char *command_begin, unsigned char *command_end); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /lib/compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef _compiler_h_ 2 | #define _compiler_h_ 3 | 4 | // shitty workaround for OS X. 5 | #ifndef MAP_ANONYMOUS 6 | # define MAP_ANONYMOUS MAP_ANON 7 | #endif 8 | 9 | 10 | void jit_run(unsigned char *command, size_t size); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /scripts/helloworld.fck: -------------------------------------------------------------------------------- 1 | ++++++++++ 2 | [ 3 | >+++++++ 4 | >++++++++++>+++>+ 5 | <<<<- 6 | ] 7 | 8 | 9 | >++. 10 | >+. 11 | +++++++.. 12 | +++. 13 | >++. 14 | <<+++++++++++++++. 15 | >. 16 | +++. 17 | ------. 18 | --------. 19 | >+. 20 | >. 21 | -------------------------------------------------------------------------------- /possible-extensions.md: -------------------------------------------------------------------------------- 1 | * Fix the RWX memory: make it RW for code generation and RX for execution (see mprotect (2)) 2 | 3 | * Add an option to dump the code to binary 4 | * Implement the read syscall for getchar() 5 | 6 | * Implement operation combination: `>>>` should result in `add rdx, 3` instead of 3 times ` add rdx, 1`. 7 | 8 | -------------------------------------------------------------------------------- /asm/print_linux.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | mov rax, 1 ; write is syscall number 1 4 | mov rdi, 1 ; write to stdout 5 | mov rsi, rdx ; rdx is the address of the one character string [rdx] (doesn't need a NUL byte since we specify the length of the message) 6 | push rdx ; save rdx to stack 7 | mov rdx, 1 ; size of message 8 | syscall ; yay write 9 | pop rdx ; restore rdx 10 | -------------------------------------------------------------------------------- /lib/utils/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _stack_h_ 2 | #define _stack_h_ 3 | 4 | typedef struct { 5 | size_t size; 6 | size_t used_size; 7 | size_t element_size; 8 | void *el; 9 | } stack; 10 | 11 | stack *stack_create(size_t element_size); 12 | void stack_push(stack *s, void *elem); 13 | 14 | void stack_pop(stack *s, void *pop_here); 15 | int stack_empty(stack *s); 16 | 17 | void stack_destroy(stack *s); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /asm/print_osx.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | 3 | mov rax, 0x200018d ; write_nocancel is used by libc 4 | mov rdi, 1 ; to stdout 5 | mov rsi, rdx ; rdx is the address of the one character string [rdx] (doesn't need a NUL byte since we specify the length of the message) 6 | push rdx ; save rdx to stack 7 | mov rdx, 1 ; size of message 8 | syscall 9 | pop rdx ; restore rdx 10 | -------------------------------------------------------------------------------- /lib/gettime.c: -------------------------------------------------------------------------------- 1 | #ifdef WIN32 2 | #include 3 | double get_time() { 4 | LARGE_INTEGER t, f; 5 | QueryPerformanceCounter(&t); 6 | QueryPerformanceFrequency(&f); 7 | return (double)t.QuadPart/(double)f.QuadPart; 8 | } 9 | #else 10 | #include 11 | #include 12 | double get_time() { 13 | struct timeval t; 14 | struct timezone tzp; 15 | gettimeofday(&t, &tzp); 16 | return t.tv_sec + t.tv_usec*1e-6; 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /scripts/fibonacci.fck: -------------------------------------------------------------------------------- 1 | +++++++++++ 2 | >+>>>>++++++++++++++++++++++++++++++++++++++++++++ 3 | >++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+> 4 | +<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[- 5 | <-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<< 6 | -]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]] 7 | >[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++ 8 | +++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++ 9 | ++++++++++++++++++++++++++++++++++++++++++++.[-]<< 10 | <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<< 11 | [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-] -------------------------------------------------------------------------------- /scripts/helloworld_commented_execution.fck: -------------------------------------------------------------------------------- 1 | ++++++++++ C0 = 10 Loop counter 2 | [ 3 | >+++++++ C1 += 7 4 | >++++++++++ C2 += 10 5 | >+++ C3 += 3 6 | >+ C4 += 1 7 | <<<<- C0-- 8 | ] 9 | 10 | At this point: 11 | C0 = 0 12 | C1 = 70 13 | C2 = 100 14 | C3 = 30 15 | C4 = 10 16 | 17 | >++. C1 += 2; 72 = H 18 | >+. C2 += 1; 101 = e 19 | +++++++.. C2 += 7; 108 = ll 20 | +++. C2 += 3; 111 = o 21 | >++. C3 += 2; 32 22 | <<+++++++++++++++. 23 | >. 24 | +++. 25 | ------. 26 | --------. 27 | >+. 28 | >. 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O0 -Ilib -std=gnu99 -m64 -Wno-pointer-sign -DPLAYGROUND_CELLS=30000 -DNDEBUG 2 | 3 | SOURCES=$(wildcard lib/**/*.c lib/*.c) 4 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 5 | 6 | ASM=$(wildcard asm/*.asm) 7 | ASMBIN=$(patsubst %.asm,%.bin,$(ASM)) 8 | 9 | TARGET=brain 10 | 11 | all: $(TARGET) tags 12 | 13 | $(TARGET): $(OBJECTS) 14 | 15 | asm: $(ASMBIN) 16 | 17 | %.bin: %.asm 18 | nasm -f bin $< -o $@ 19 | 20 | tags: $(SOURCES) 21 | @(ctags -R --exclude=asm . || true) 22 | 23 | clean: 24 | @rm -rf $(TARGET) $(TARGET).dSYM $(OBJECTS) $(ASMBIN) tags peda-* 25 | 26 | .PHONY: tags clean asm 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the organization nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /brain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | int main(int argc, char **argv) { 15 | unsigned char *command_file = NULL; 16 | int use_interpreter = 0; 17 | 18 | FILE *script_file = NULL; 19 | char *script_path = argv[argc - 1]; 20 | 21 | check(argc == 2 || argc == 3, "Usage: %s [--interpreter|--JIT] [script|-]", argv[0]); 22 | 23 | if(strcmp(argv[1], "--interpreter") == 0) { 24 | debug("Using interpreter"); 25 | use_interpreter = 1; 26 | } else { 27 | debug("Using JIT compiler"); 28 | } 29 | 30 | if(strcmp(script_path, "-") == 0) { 31 | script_file = stdin; 32 | } else { 33 | script_file = fopen(script_path, "r"); 34 | } 35 | check(script_file != NULL, "Couldn't open script %s", script_path); 36 | 37 | // get size of brainfuck instructions file 38 | fseek(script_file, 0L, SEEK_END); 39 | size_t command_size = ftell(script_file); 40 | fseek(script_file, 0L, SEEK_SET); 41 | 42 | 43 | debug("command_size: %zu", command_size); 44 | 45 | // read instructions file to hand it to the interpreter/compiler 46 | command_file = malloc(command_size); 47 | check_mem(command_file); 48 | 49 | size_t read_bytes = fread(command_file, 1, command_size, script_file); 50 | check(read_bytes == command_size, "fread() failed to read the script"); 51 | fclose(script_file); 52 | 53 | if(use_interpreter) { 54 | interpreter_main_loop(command_file, command_file + command_size); 55 | } 56 | else { 57 | jit_run(command_file, command_size); 58 | } 59 | 60 | error: 61 | if(command_file) { 62 | free(command_file); 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /lib/utils/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static size_t DEFAULT_STACK_ELEMENTS = 8; 7 | 8 | stack *stack_create(size_t element_size) { 9 | stack *s = malloc(sizeof(stack)); 10 | check_mem(s); 11 | s->size = DEFAULT_STACK_ELEMENTS; 12 | s->used_size = 0; 13 | s->element_size = element_size; 14 | s->el = calloc(element_size, s->size); 15 | return s; 16 | 17 | error: 18 | if(s) { 19 | stack_destroy(s); 20 | } 21 | return NULL; 22 | } 23 | 24 | static void stack_grow(stack *s) { 25 | s->size = 2 * s->size + 1; 26 | s->el = realloc(s->el, s->size * s->element_size); 27 | } 28 | 29 | static void stack_shrink(stack *s) { 30 | s->size = s->size / 2; 31 | assert(s->size >= s->used_size); 32 | s->el = realloc(s->el, s->size * s->element_size); 33 | } 34 | 35 | void stack_push(stack *s, void *elem) { 36 | if(s->size <= s->used_size) { 37 | stack_grow(s); 38 | } 39 | void *above_top = s->el + s->used_size * s->element_size; 40 | memcpy(above_top, elem, s->element_size); 41 | s->used_size++; 42 | } 43 | 44 | void stack_pop(stack *s, void *pop_here) { 45 | if(stack_empty(s)) { 46 | return; 47 | } 48 | void *top = s->el + (s->used_size - 1) * s->element_size; 49 | memcpy(pop_here, top, s->element_size); 50 | s->used_size--; 51 | 52 | if (s->size > 2 * s->used_size) { 53 | stack_shrink(s); 54 | } 55 | } 56 | 57 | int stack_empty(stack *s) { 58 | return s->used_size == 0; 59 | } 60 | 61 | void stack_destroy(stack *s) { 62 | if (s->el) free(s->el); 63 | free(s); 64 | } 65 | 66 | 67 | static void stack_test_all() { 68 | stack *s = stack_create(sizeof(int)); 69 | int a = 0x69; 70 | int b = 0xabad1dea; 71 | stack_push(s, &a); 72 | stack_push(s, &b); 73 | 74 | int c; 75 | stack_pop(s, &c); 76 | printf("popped c is %d and should be same as b, %d\n", c, b); 77 | stack_pop(s, &c); 78 | printf("popped c is %d and should be same as a, %d\n", c, a); 79 | stack_destroy(s); 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `jit_brainfuck` 2 | ============== 3 | A JIT compiler for brainfuck on x86_64. Its internals and an introduction to brainfuck are available on [my website](https://toastedcornflakes.github.io/articles/jit-brainfuck.html). 4 | 5 | How to run: 6 | ---------- 7 | Currently, `jit_brainfuck` runs on OS X and linux 64 bits, and a Dockerfile for [docker](https://www.docker.com/) is provided. 8 | 9 | To build and run natively: 10 | 11 | make 12 | ./brain [--intepreter|--jit] script.fck 13 | 14 | 15 | The [interpreter](lib/interpreter.c) reads one character at the time from the brainfuck script, execute the corresponding operation on the `instruction_pointer` or `cell_pointer`. 16 | 17 | The [jit compiler](lib/compiler.c) reads the whole file and generates x64 assembly corresponding to the brainfuck instructions. It does so in one pass, without any optimisation. 18 | 19 | 20 | Example 21 | ------- 22 | The generated assembly from [hello script](scripts/hello.fck) looks like this. 23 | 24 | It matches 1:1 with the brainfuck instructions: 25 | 26 | ; set up register for memory handing 27 | 0x100037000: movabs rdx,0x100803200 28 | 29 | 0x10003700a: add BYTE PTR [rdx],0x1 30 | 0x10003700d: add BYTE PTR [rdx],0x1 31 | 0x100037010: add BYTE PTR [rdx],0x1 32 | 0x100037025: add BYTE PTR [rdx],0x1 33 | ... snip ... 34 | 35 | ; start of loop 36 | 0x100037028: jmp 0x10003708f 37 | 0x10003702d: add rdx,0x1 38 | 0x100037031: add BYTE PTR [rdx],0x1 39 | 0x100037034: add BYTE PTR [rdx],0x1 40 | ... snip ... 41 | 0x100037088: sub rdx,0x1 42 | 43 | ; end loop 44 | 0x10003708c: sub BYTE PTR [rdx],0x1 45 | 0x10003708f: cmp BYTE PTR [rdx],0x0 46 | 0x100037092: jne 0x10003702d 47 | 48 | 0x10003709f: add BYTE PTR [rdx],0x1 49 | 50 | ; make a write syscall 51 | 0x1000370a2: mov eax,0x200018d 52 | 0x1000370a7: mov edi,0x1 53 | 0x1000370ac: mov rsi,rdx 54 | 0x1000370af: push rdx 55 | 0x1000370b0: mov edx,0x1 56 | 0x1000370b5: syscall 57 | 0x1000370b7: pop rdx 58 | ... snip ... 59 | 60 | ; end of program 61 | 0x100037135: ret 62 | 63 | License 64 | ------- 65 | BSD 3-clause. See [LICENSE](LICENSE). 66 | -------------------------------------------------------------------------------- /lib/interpreter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | // will fetch one brainfuck instruction at a time and execute it 9 | void interpreter_main_loop(unsigned char *command_begin, unsigned char *command_end) { 10 | unsigned char *begin_cells = calloc(1, PLAYGROUND_CELLS); 11 | check_mem(begin_cells); 12 | 13 | unsigned char *cell_pointer = begin_cells; 14 | unsigned char *instruction_pointer = command_begin; 15 | 16 | 17 | /* safe loop version: 18 | while(instruction_pointer >= command_begin && instruction_pointer < command_end && 19 | cell_pointer >= begin_cells && cell_pointer < begin_cells + PLAYGROUND_CELLS) 20 | */ 21 | 22 | 23 | // the loop has NO safety checks whatsoever 24 | while(instruction_pointer < command_end) { 25 | unsigned char command = *instruction_pointer; 26 | switch (command) { 27 | case '>': 28 | cell_pointer++; 29 | break; 30 | case '<': 31 | cell_pointer--; 32 | break; 33 | case '+': 34 | (*cell_pointer)++; 35 | break; 36 | case '-': 37 | (*cell_pointer)--; 38 | break; 39 | case '.': 40 | putchar(*cell_pointer); 41 | break; 42 | case',': 43 | // getchar returns an int 44 | *cell_pointer = (unsigned char)getchar(); 45 | break; 46 | 47 | // control flow stuff 48 | case'[': 49 | // if *cell_pointer == 0, jump to CORRESPONDING (not next!) ] 50 | if (*cell_pointer == 0) { 51 | int count = 0; 52 | while (1) { 53 | if (*instruction_pointer == '[') { 54 | count++; 55 | } else if (*instruction_pointer == ']') { 56 | if(--count == 0) { 57 | break; 58 | } 59 | } 60 | instruction_pointer++; 61 | } 62 | } 63 | break; 64 | case ']': 65 | if (*cell_pointer != 0) { 66 | // jump to CORRESPONDING (not prev!) `[` 67 | int count = 0; 68 | while (1) { 69 | if (*instruction_pointer == ']') { 70 | count++; 71 | } else if (*instruction_pointer == '[') { 72 | if(--count == 0) { 73 | break; 74 | } 75 | } 76 | instruction_pointer--; 77 | } 78 | } 79 | break; 80 | } 81 | instruction_pointer++; 82 | } 83 | 84 | error: 85 | if(begin_cells) { 86 | free(begin_cells); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /lib/dbg.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010, Zed A. Shaw. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the Learn C The Hard Way, Zed A. Shaw, nor the names 16 | of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written 18 | permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef _dbg_h_ 34 | #define _dbg_h_ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef NDEBUG 41 | #define debug(M, ...) 42 | #else 43 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 44 | #endif 45 | 46 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 47 | 48 | #define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 49 | 50 | #define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 51 | 52 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 53 | 54 | #define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } 55 | 56 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } 57 | 58 | #define check_mem(A) check((A), "Out of memory.") 59 | 60 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /lib/compiler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | /* Conventions used in the generated code: 13 | %rip is the instruction pointer 14 | %rdx is the pointer to current memory cell (rdx wasn't chosen for any particular reason) */ 15 | 16 | typedef void (*jitted_code)(); 17 | 18 | /* Allocs a RWX page using mmap. */ 19 | void *alloc_executable_memory(size_t size) { 20 | void* ptr = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 21 | check(ptr != MAP_FAILED && ptr != NULL, "Couldn't mmap RWX page"); 22 | 23 | return ptr; 24 | 25 | error: 26 | return NULL; 27 | } 28 | 29 | 30 | /* Convert brainfuck instruction to x64 code, returned in **code, with code size size in *size. 31 | Invalid brainfuck instructions (aka comments) returns NULL 32 | Note: asm files that generated the x64 hex are in the asm/ directory */ 33 | static void code_for_instruction(unsigned char instruction, unsigned char **code, size_t *size) { 34 | switch (instruction) { 35 | case '>': 36 | *code = "\x48\x83\xc2\x01"; // code for cc++, aka add rdx, 1 37 | *size = 4; 38 | return; 39 | case '<': 40 | *code = "\x48\x83\xea\x01"; // code for cc--, aka sub rdx, 1 41 | *size = 4; 42 | return; 43 | 44 | case '+': 45 | *code = "\x80\x02\x01"; // code for (*cc)++, aka add [rdx], 1 46 | *size = 3; 47 | return; 48 | case '-': 49 | *code = "\x80\x2a\x01"; // (*cc)-- 50 | *size = 3; 51 | return; 52 | case '.': 53 | #ifdef __APPLE__ 54 | // OS X syscalls are a bit different 55 | //*code = "\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x89\xd6\x52\xba\x01\x00\x00\x00\x0f\x05\x5a"; // write() 56 | *code = "\xb8\x8d\x01\x00\x02\xbf\x01\x00\x00\x00\x48\x89\xd6\x52\xba\x01\x00\x00\x00\x0f\x05\x5a"; // write_nocancel() 57 | *size = 22; 58 | #else 59 | *code = "\xb8\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x89\xd6\x52\xba\x01\x00\x00\x00\x0f\x05\x5a"; // print char stored at [rdx] 60 | *size = 22; 61 | #endif 62 | return; 63 | default: 64 | *code = NULL; 65 | *size = -1; 66 | } 67 | } 68 | 69 | // TODO: refactor the code generation process to be instruction type agnostic 70 | size_t compute_machine_code_size(unsigned char *command, size_t command_size) { 71 | size_t size = 3; // size for setting up rdx + ret 72 | unsigned char dummy[64]; 73 | 74 | for (unsigned char *cur_command = command; cur_command < command + command_size; cur_command++) { 75 | if (*cur_command == '[') { 76 | size += 5; 77 | } 78 | else if (*cur_command == ']') { 79 | size += 9; 80 | } 81 | else { 82 | size_t tmp = 0; 83 | code_for_instruction(*cur_command, (void*)&dummy, &tmp); 84 | size += tmp; 85 | } 86 | } 87 | return size; 88 | } 89 | 90 | 91 | /* This function compiles and execute the `size` brainfucks instructions in `command` 92 | */ 93 | void jit_run(unsigned char *command, size_t command_size) { 94 | // create the data space of the program 95 | unsigned char *begin_cells = calloc(1, PLAYGROUND_CELLS); 96 | check_mem(begin_cells); 97 | 98 | size_t code_size = compute_machine_code_size(command, command_size); 99 | unsigned char *big_chunk = alloc_executable_memory(code_size); 100 | unsigned char *code = big_chunk; 101 | 102 | // add code to set rdx to address of playground 103 | code[0] = 0x48; 104 | code[1] = 0xba; 105 | code += 2; 106 | memcpy(code, &begin_cells, sizeof(unsigned char *)); 107 | code += sizeof(unsigned char*); 108 | 109 | stack *jumpback_stack = stack_create(sizeof(unsigned char*)); 110 | 111 | for (unsigned char *cur_command = command; cur_command < command + command_size; cur_command++) { 112 | //debug("decoding command #%d", ++n); 113 | unsigned char *ins_code = NULL; 114 | size_t size; 115 | 116 | if (*cur_command == '[') { 117 | // will be filled later by the corresponding '[' 118 | unsigned char base[5] = "\xe9 FLL"; 119 | 120 | ins_code = base; 121 | size = 5; 122 | 123 | // note the current position (offset from start) for later use 124 | unsigned char *next_ins = (unsigned char*)(code + size - big_chunk); 125 | stack_push(jumpback_stack, &next_ins); 126 | } 127 | else if (*cur_command == ']') { 128 | check(!stack_empty(jumpback_stack), "Mismatched '[' or ']' in input"); 129 | 130 | // jump is implemented in the form of jmp [RIP + const] 131 | unsigned char *addr; 132 | stack_pop(jumpback_stack, &addr); 133 | addr += (size_t)big_chunk; 134 | 135 | size = 9; 136 | // jump address relative to next instruction => needs to account for size of current jump instruction 137 | uint32_t jump_offset = addr - code - size; 138 | debug("Making a %d bytes jump", jump_offset); 139 | unsigned char base[9] = "\x80\x3a\x00\x0f\x85 "; 140 | memcpy(&base[5], &jump_offset,4); 141 | 142 | ins_code = base; 143 | 144 | // now we also need to make the previous [ unconditionnaly jump here 145 | // just putting the current address there, relatively speaking 146 | uint32_t forward_offset = -(addr - code); 147 | memcpy(addr - 4, &forward_offset, 4); 148 | 149 | } 150 | else { 151 | // it's not a branch instruction, nothing special to do 152 | code_for_instruction(*cur_command, &ins_code, &size); 153 | } 154 | 155 | // copy instruction to executable page 156 | // ignoring comments 157 | if(ins_code) { 158 | memcpy(code, ins_code, size); 159 | code += size; 160 | } 161 | } 162 | 163 | // add `ret` to exit cleanly: 164 | code[0] = 0xc3; 165 | code++; 166 | 167 | jitted_code func = (jitted_code)big_chunk; 168 | 169 | debug("Running compiled code."); 170 | func(); 171 | 172 | error: 173 | if (begin_cells) { 174 | free(begin_cells); 175 | } 176 | return; 177 | } 178 | 179 | -------------------------------------------------------------------------------- /scripts/mandelbrot.b: -------------------------------------------------------------------------------- 1 | A mandelbrot set fractal viewer in brainf*** written by Erik Bosman 2 | +++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[ 3 | >>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+ 4 | <<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>> 5 | >+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>> 6 | >>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>> 7 | >>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>> 8 | >>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>> 9 | [>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<< 10 | <<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[ 11 | >>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[ 12 | >+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[ 13 | -<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<< 14 | <<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<< 15 | [>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>> 16 | >>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+ 17 | <<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>> 18 | >>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<< 19 | +>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<< 20 | <]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>> 21 | >>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> 22 | >>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<< 23 | <<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<< 24 | <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[-> 25 | >>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<< 26 | <<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++ 27 | +++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>- 28 | <<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>> 29 | [-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<< 30 | <+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[- 31 | ]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<< 32 | <<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]< 33 | <[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>> 34 | >>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>> 35 | [-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-< 36 | <<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>> 37 | ]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+ 38 | >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> 39 | [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- 40 | ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> 41 | [>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 42 | ]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+> 43 | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++ 44 | +++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+ 45 | >>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[ 46 | -]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-< 47 | <<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<< 48 | [->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-] 49 | +>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<< 50 | <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<< 51 | [<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<< 52 | <<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<< 53 | <<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<< 54 | <<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<< 55 | <<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<< 56 | <<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<< 57 | ]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<< 58 | [>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<< 59 | +>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<< 60 | <<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-< 61 | <<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[ 62 | [>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+ 63 | [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->> 64 | [-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<< 65 | <[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[ 66 | >[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[ 67 | >>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]> 68 | >>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<< 69 | <<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<< 70 | <<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[- 71 | <<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>> 72 | >>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>> 73 | [-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<< 74 | +>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]> 75 | [-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>> 76 | >>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>> 77 | >>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<< 78 | ]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<< 79 | <+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>> 80 | >]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<< 81 | <<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<< 82 | <<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]< 83 | <<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]< 84 | <<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+ 85 | <]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>- 86 | <<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<< 87 | ]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+> 88 | >>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>- 89 | <<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[ 90 | ->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>> 91 | >>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>> 92 | >>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<< 93 | <<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<< 94 | <<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+ 95 | >>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>> 96 | ]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> 97 | >>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>> 98 | >>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+ 99 | >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> 100 | [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- 101 | ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> 102 | [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<< 103 | <<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>> 104 | >>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>> 105 | >>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+ 106 | <<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>> 107 | >>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>> 108 | >]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<] 109 | >>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<< 110 | ]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+< 111 | <<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]> 112 | >>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<< 113 | ->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[ 114 | >[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<< 115 | [<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<< 116 | <<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<< 117 | <<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<< 118 | <<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>> 119 | >+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<< 120 | <<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]< 121 | +<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>> 122 | >>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<< 123 | <<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<< 124 | <<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<< 125 | <<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-< 126 | <<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<< 127 | <<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<< 128 | <<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<< 129 | <<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>> 130 | >+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<< 131 | <<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>> 132 | >]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<< 133 | <<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>> 134 | >>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<- 135 | >>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<< 136 | <<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>> 137 | >>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<< 138 | <<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>> 139 | +>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+< 140 | <<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<< 141 | <<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>> 142 | -<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>> 143 | >>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++ 144 | +[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<< 145 | <<<<<]]>>>] 146 | --------------------------------------------------------------------------------