├── .gitignore ├── AUTHORS ├── LICENSE ├── Makefile ├── README.md ├── compiler-arm.c ├── compiler-x64.c ├── compiler-x86.c ├── dynasm-driver.c ├── dynasm ├── COPYRIGHT ├── README ├── dasm_arm.h ├── dasm_arm.lua ├── dasm_arm64.h ├── dasm_arm64.lua ├── dasm_mips.h ├── dasm_mips.lua ├── dasm_ppc.h ├── dasm_ppc.lua ├── dasm_proto.h ├── dasm_x64.lua ├── dasm_x86.h ├── dasm_x86.lua └── dynasm.lua ├── interpreter.c ├── jit-arm.dasc ├── jit-x64.dasc ├── jit-x86.dasc ├── progs ├── awib.b ├── echo.b ├── hanoi.b ├── hello.b ├── mandelbrot.b ├── oobrain.b ├── sierpinski.b └── test.b ├── tests ├── bench.py ├── jit0-arm.c ├── jit0-x64.c └── test_stack.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.exe 3 | test_stack 4 | test_vector 5 | compiler-arm 6 | compiler-x64 7 | compiler-x86 8 | interpreter 9 | jit-x86 10 | jit-x86.h 11 | jit-x64 12 | jit-x64.h 13 | jit-arm 14 | jit-arm.h 15 | jit0-x64 16 | jit0-arm 17 | hello-arm 18 | hello-x64 19 | hello-x86 20 | hello.s 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | jit-construct is derived from the great work of Nick Desaulniers. 2 | original work: https://github.com/nickdesaulniers/bf_interpreter_jit_compiler 3 | 4 | Contributors: 5 | Jim Huang 6 | Yen-Chin Lee 7 | Yan-Hsuan Chuang 8 | Yu-Ju Huang 9 | Shu-Hung You 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | jit-construct is derived from the great work of Nick Desaulniers: 2 | https://github.com/nickdesaulniers/bf_interpreter_jit_compiler 3 | 4 | jit-construct is freely redistributable under the two-clause BSD 5 | License: 6 | 7 | Copyright (C) 2015 The JIT-Construct Authors 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimer. 16 | 2. Redistributions in binary form must reproduce the above copyright notice, 17 | this list of conditions and the following disclaimer in the documentation 18 | and/or other materials provided with the distribution. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = interpreter \ 2 | compiler-x86 compiler-x64 compiler-arm \ 3 | jit-x86 jit-x64 jit-arm 4 | 5 | CROSS_COMPILE = arm-linux-gnueabihf- 6 | QEMU_ARM = qemu-arm -L /usr/arm-linux-gnueabihf 7 | LUA = luajit 8 | 9 | all: $(BIN) 10 | 11 | CFLAGS = -Wall -Werror -std=gnu99 -I. 12 | 13 | interpreter: interpreter.c 14 | $(CC) $(CFLAGS) -o $@ $^ 15 | 16 | compiler-x86: compiler-x86.c 17 | $(CC) $(CFLAGS) -o $@ $^ 18 | 19 | compiler-x64: compiler-x64.c 20 | $(CC) $(CFLAGS) -o $@ $^ 21 | 22 | compiler-arm: compiler-arm.c 23 | $(CC) $(CFLAGS) -o $@ $^ 24 | 25 | run-compiler: compiler-x86 compiler-x64 compiler-arm 26 | ./compiler-x86 progs/hello.b > hello.s 27 | $(CC) -m32 -o hello-x86 hello.s 28 | @echo 'x86: ' `./hello-x86` 29 | @echo 30 | ./compiler-x64 progs/hello.b > hello.s 31 | $(CC) -o hello-x64 hello.s 32 | @echo 'x64: ' `./hello-x64` 33 | @echo 34 | ./compiler-arm progs/hello.b > hello.s 35 | $(CROSS_COMPILE)gcc -o hello-arm hello.s 36 | @echo 'arm: ' `$(QEMU_ARM) hello-arm` 37 | @echo 38 | 39 | jit0-x64: tests/jit0-x64.c 40 | $(CC) $(CFLAGS) -o $@ $^ 41 | 42 | jit-x86: dynasm-driver.c jit-x86.h 43 | $(CC) $(CFLAGS) -o $@ -DJIT=\"jit-x86.h\" \ 44 | dynasm-driver.c -m32 45 | jit-x86.h: jit-x86.dasc 46 | $(LUA) dynasm/dynasm.lua -o $@ jit-x86.dasc 47 | run-jit-x86: jit-x86 48 | ./jit-x86 progs/hello.b && objdump -D -b binary \ 49 | -mi386 -Mx86 /tmp/jitcode 50 | 51 | jit-x64: dynasm-driver.c jit-x64.h 52 | $(CC) $(CFLAGS) -o $@ -DJIT=\"jit-x64.h\" \ 53 | dynasm-driver.c 54 | jit-x64.h: jit-x64.dasc 55 | $(LUA) dynasm/dynasm.lua -o $@ jit-x64.dasc 56 | run-jit-x64: jit-x64 57 | ./jit-x64 progs/hello.b && objdump -D -b binary \ 58 | -mi386 -Mx86-64 /tmp/jitcode 59 | 60 | jit0-arm: tests/jit0-arm.c 61 | $(CROSS_COMPILE)gcc $(CFLAGS) -o $@ $^ 62 | 63 | jit-arm: dynasm-driver.c jit-arm.h 64 | $(CROSS_COMPILE)gcc $(CFLAGS) -o $@ -DJIT=\"jit-arm.h\" \ 65 | dynasm-driver.c 66 | jit-arm.h: jit-arm.dasc 67 | $(LUA) dynasm/dynasm.lua -o $@ jit-arm.dasc 68 | run-jit-arm: jit-arm 69 | $(QEMU_ARM) jit-arm progs/hello.b && \ 70 | $(CROSS_COMPILE)objdump -D -b binary -marm /tmp/jitcode 71 | 72 | bench-jit-x86: jit-x86 73 | @echo 74 | @echo Executing Brainf*ck benchmark suite. Be patient. 75 | @echo 76 | @env PATH='.:${PATH}' BF_RUN='$<' tests/bench.py 77 | 78 | bench-jit-x64: jit-x64 79 | @echo 80 | @echo Executing Brainf*ck benchmark suite. Be patient. 81 | @echo 82 | @env PATH='.:${PATH}' BF_RUN='$<' tests/bench.py 83 | 84 | test: test_stack jit0-x64 jit0-arm 85 | ./test_stack 86 | (./jit0-x64 42 ; echo $$?) 87 | ($(QEMU_ARM) jit0-arm 42 ; echo $$?) 88 | 89 | test_stack: tests/test_stack.c 90 | $(CC) $(CFLAGS) -o $@ $^ 91 | 92 | clean: 93 | $(RM) $(BIN) \ 94 | hello-x86 hello-x64 hello-arm hello.s \ 95 | test_stack jit0-x64 jit0-arm \ 96 | jit-x86.h jit-x64.h jit-arm.h 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Interpreter, Compiler, JIT 2 | This repository contains the programs used in Nick Desaulniers' [blog post](https://nickdesaulniers.github.io/blog/2015/05/25/interpreter-compiler-jit/); an interpreter, a compiler, and a Just In Time (JIT) compiler for the brainfuck language. It is meant to show how similar these techniques are, and then improved by several students who learnt system programming to bring X86/ARM backend along with [DynASM](http://luajit.org/dynasm.html) support. 3 | 4 | ## Portability 5 | While all three are written in C, only the interpreter should be portable, even to [Emscripten](https://github.com/kripken/emscripten). The compiler and JIT is highly dependant on the specific Instruction Set Architecture (ISA), and Linux style calling convention. 6 | 7 | ## Prerequisites 8 | Development packages for Ubuntu Linux Ubuntu: 9 | 10 | ```shell 11 | sudo apt-get update 12 | sudo apt-get install build-essential 13 | sudo apt-get install gcc-multilib 14 | sudo apt-get install luajit 15 | sudo apt-get install gcc-arm-linux-gnueabihf 16 | sudo apt-get install qemu-user 17 | ``` 18 | 19 | ## Building 20 | 21 | ```shell 22 | make 23 | ``` 24 | 25 | ## Running 26 | ### The Interpreter 27 | 28 | ```shell 29 | ./interpreter progs/hello.bf 30 | ``` 31 | 32 | ### The Compiler 33 | 34 | ```shell 35 | make run-compiler 36 | ``` 37 | 38 | ### The JIT 39 | 40 | ```shell 41 | make run-jit-x86 42 | make run-jit-x64 43 | make run-jit-arm 44 | make bench-jit-x86 45 | make bench-jit-x64 46 | ``` 47 | 48 | ## License 49 | 50 | _Except_ the code in `progs/` and `dynasm/`, the JIT-Construct source files are distributed 51 | BSD-style license found in the LICENSE file. 52 | 53 | External sources: 54 | * [DynASM](http://luajit.org/dynasm.html) is a tiny preprocessor and runtime for generating machine code at runtime and copyrighted by Mike Pall, released under the MIT license. 55 | * `progs/mandelbrot.b` is a mandelbrot set fractal viewer in brainfuck written by Erik Bosman. 56 | * `progs/sierpinski.b` is written by [NYYRIKKI](http://www.iwriteiam.nl/Ha_vs_bf_inter.html). 57 | * `progs/awib.b` is written by [Mats Linander](https://github.com/matslina/awib). 58 | * `progs/hanoi.b` is written by [Clifford Wolf](http://www.clifford.at/bfcpu/hanoi.html). 59 | * `progs/oobrain.b` is written by [Chris Rathman](http://www.angelfire.com/tx4/cus/shapes/brain.html) 60 | -------------------------------------------------------------------------------- /compiler-arm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | void compile(const char * const file_contents) 6 | { 7 | int num_brackets = 0; 8 | int matching_bracket = 0; 9 | struct stack stack = { .size = 0, .items = { 0 } }; 10 | const char * const prologue = 11 | ".globl main\n" 12 | "main:\n" 13 | "LDR R4 ,= _array\n" 14 | "push {lr}\n"; 15 | puts(prologue); 16 | 17 | for (unsigned long i = 0; file_contents[i] != '\0'; ++i) { 18 | switch (file_contents[i]) { 19 | case '>': 20 | puts(" ADD R4, R4, #1"); 21 | break; 22 | case '<': 23 | puts(" SUB R4, R4, #1"); 24 | break; 25 | case '+': 26 | puts(" LDRB R5, [R4]"); 27 | puts(" ADD R5, R5, #1"); 28 | puts(" STRB R5, [R4]"); 29 | break; 30 | case '-': 31 | puts(" LDRB R5, [R4]"); 32 | puts(" SUB R5, R5, #1"); 33 | puts(" STRB R5, [R4]"); 34 | break; 35 | case '.': 36 | puts(" LDR R0 ,= _char "); 37 | puts(" LDRB R1, [R4]"); 38 | puts(" BL printf"); 39 | break; 40 | case ',': 41 | puts(" BL getchar"); 42 | puts(" STRB R0, [R4]"); 43 | break; 44 | case '[': 45 | if (stack_push(&stack, num_brackets) == 0) { 46 | printf("_in_%d:\n", num_brackets); 47 | puts (" LDRB R5, [R4]"); 48 | puts (" CMP R5, #0"); 49 | printf(" BEQ _out_%d\n", num_brackets); 50 | num_brackets++; 51 | } else { 52 | err("out of stack space, too much nesting"); 53 | } 54 | break; 55 | case ']': 56 | if (stack_pop(&stack, &matching_bracket) == 0) { 57 | printf("_out_%d:\n", matching_bracket); 58 | puts (" LDRB R5, [R4]"); 59 | puts (" CMP R5, #0"); 60 | printf(" BNE _in_%d\n", matching_bracket); 61 | } else { 62 | err("stack underflow, unmatched brackets"); 63 | } 64 | break; 65 | } 66 | } 67 | const char *const epilogue = 68 | " pop {pc}\n" 69 | ".data\n" 70 | ".align 4\n" 71 | "_char: .asciz \"%c\"\n" 72 | "_array: .space 30000\n"; 73 | puts(epilogue); 74 | } 75 | 76 | int main(int argc, char *argv[]) 77 | { 78 | if (argc != 2) err("Usage: compiler-arm "); 79 | char *file_contents = read_file(argv[1]); 80 | if (file_contents == NULL) err("Unable to read file"); 81 | compile(file_contents); 82 | free(file_contents); 83 | } 84 | -------------------------------------------------------------------------------- /compiler-x64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | void compile(const char * const text_body) 6 | { 7 | int num_brackets = 0; 8 | int matching_bracket = 0; 9 | struct stack stack = { .size = 0, .items = { 0 } }; 10 | const char * const prologue = 11 | ".text\n" 12 | ".global main\n" 13 | "main:\n" 14 | " pushq %rbp\n" 15 | " movq %rsp, %rbp\n" 16 | " pushq %r12\n" // store callee saved register 17 | " subq $30008, %rsp\n" // allocate 30,008 B on stack, and realign 18 | " leaq (%rsp), %rdi\n" // address of beginning of tape 19 | " movl $0, %esi\n" // fill with 0's 20 | " movq $30000, %rdx\n" // length 30,000 B 21 | " call memset\n" // memset 22 | " movq %rsp, %r12"; 23 | puts(prologue); 24 | 25 | for (unsigned long i = 0; text_body[i] != '\0'; ++i) { 26 | switch (text_body[i]) { 27 | case '>': 28 | puts(" inc %r12"); 29 | break; 30 | case '<': 31 | puts(" dec %r12"); 32 | break; 33 | case '+': 34 | puts(" incb (%r12)"); 35 | break; 36 | case '-': 37 | puts(" decb (%r12)"); 38 | break; 39 | case '.': 40 | // move byte to double word and zero upper bits 41 | // since putchar takes an int. 42 | puts(" movzbl (%r12), %edi"); 43 | puts(" call putchar"); 44 | break; 45 | case ',': 46 | puts(" call getchar"); 47 | puts(" movb %al, (%r12)"); 48 | break; 49 | case '[': 50 | if (stack_push(&stack, num_brackets) == 0) { 51 | puts (" cmpb $0, (%r12)"); 52 | printf(" je bracket_%d_end\n", num_brackets); 53 | printf("bracket_%d_start:\n", num_brackets++); 54 | } else { 55 | err("out of stack space, too much nesting"); 56 | } 57 | break; 58 | case ']': 59 | if (stack_pop(&stack, &matching_bracket) == 0) { 60 | puts(" cmpb $0, (%r12)"); 61 | printf(" jne bracket_%d_start\n", matching_bracket); 62 | printf("bracket_%d_end:\n", matching_bracket); 63 | } else { 64 | err("stack underflow, unmatched brackets"); 65 | } 66 | break; 67 | } 68 | } 69 | const char *const epilogue = 70 | " addq $30008, %rsp\n" // clean up tape from stack. 71 | " popq %r12\n" // restore callee saved register 72 | " popq %rbp\n" 73 | " ret\n"; 74 | puts(epilogue); 75 | } 76 | 77 | int main(int argc, char *argv[]) 78 | { 79 | if (argc != 2) err("Usage: compiler-x64 "); 80 | char *text_body = read_file(argv[1]); 81 | if (text_body == NULL) err("Unable to read file"); 82 | compile(text_body); 83 | free(text_body); 84 | } 85 | -------------------------------------------------------------------------------- /compiler-x86.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | void compile(const char * const text_body) 6 | { 7 | int num_brackets = 0; 8 | int matching_brackets = 0; 9 | struct stack stack = { .size = 0, .items = {0}}; 10 | const char * const prologue = 11 | ".section .text\n" 12 | ".global main\n" 13 | "main:\n" 14 | " pushl %ebp\n" 15 | " movl %esp, %ebp\n" 16 | " addl $-3008, %esp\n" 17 | " leal (%esp), %edi\n" 18 | " movl $0, %esi\n" 19 | " movl $3000, %edx\n" 20 | " call memset\n" 21 | " movl %esp, %ecx"; 22 | puts(prologue); 23 | 24 | for (unsigned long i = 0; text_body[i] != '\0'; ++i) { 25 | switch (text_body[i]){ 26 | case '>': 27 | puts(" inc %ecx"); 28 | break; 29 | case '<': 30 | puts(" dec %ecx"); 31 | break; 32 | case '+': 33 | puts(" incb (%ecx)"); 34 | break; 35 | case '-': 36 | puts(" decb (%ecx)"); 37 | break; 38 | case '.': 39 | puts(" call putchar"); 40 | break; 41 | case ',': 42 | puts(" call getchar"); 43 | puts(" movb %al, (%ecx)"); 44 | break; 45 | case '[': 46 | if (stack_push(&stack, num_brackets)==0) { 47 | puts (" cmpb $0, (%ecx)"); 48 | printf(" je bracket_%d_end\n", num_brackets); 49 | printf("bracket_%d_start:\n", num_brackets++); 50 | } else { 51 | err("out of stack space"); 52 | } 53 | break; 54 | case ']': 55 | if (stack_pop(&stack, &matching_brackets)==0) { 56 | puts ("cmpb $0, (%ecx)"); 57 | printf(" jne bracket_%d_start\n", matching_brackets); 58 | printf("bracket_%d_end:\n", matching_brackets); 59 | } else { 60 | err("stack underflow, unmatched"); 61 | } 62 | break; 63 | } 64 | } 65 | const char * const epilogue = 66 | " addl $3008, %esp\n" 67 | " popl %ebp\n" 68 | " ret\n" 69 | "putchar:\n" 70 | " mov $4, %eax\n" 71 | " mov $1, %ebx\n" 72 | " mov $1, %edx\n" 73 | " int $0x80\n"; 74 | puts(epilogue); 75 | } 76 | 77 | int main(int argc, char *argv[]) 78 | { 79 | if (argc != 2) err("Usage: compile-x86 inputfile"); 80 | char *text_body = read_file(argv[1]); 81 | if (text_body == NULL) err("unable to read file"); 82 | compile(text_body); 83 | free(text_body); 84 | } 85 | -------------------------------------------------------------------------------- /dynasm-driver.c: -------------------------------------------------------------------------------- 1 | // Driver file for DynASM-based JITs. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "dynasm/dasm_proto.h" 8 | 9 | #if defined(__x86_64__) || defined(__i386) 10 | #include "dynasm/dasm_x86.h" 11 | #elif defined(__arm__) 12 | #include "dynasm/dasm_arm.h" 13 | #else 14 | #error "The architecture is not supported" 15 | #endif 16 | 17 | void initjit(dasm_State **state, const void *actionlist); 18 | void *jitcode(dasm_State **state); 19 | void free_jitcode(void *code); 20 | 21 | #include JIT 22 | 23 | void initjit(dasm_State **state, const void *actionlist) 24 | { 25 | dasm_init(state, 1); 26 | dasm_setup(state, actionlist); 27 | } 28 | 29 | void *jitcode(dasm_State **state) 30 | { 31 | size_t size; 32 | int dasm_status = dasm_link(state, &size); 33 | assert(dasm_status == DASM_S_OK); 34 | 35 | // Allocate memory readable and writable so we can 36 | // write the encoded instructions there. 37 | char *mem = mmap(NULL, size + sizeof(size_t), 38 | PROT_READ | PROT_WRITE, 39 | MAP_ANON | MAP_PRIVATE, -1, 0); 40 | assert(mem != MAP_FAILED); 41 | 42 | // Store length at the beginning of the region, so we 43 | // can free it without additional context. 44 | *(size_t *) mem = size; 45 | void *ret = mem + sizeof(size_t); 46 | 47 | dasm_encode(state, ret); 48 | dasm_free(state); 49 | 50 | // Adjust the memory permissions so it is executable 51 | // but no longer writable. 52 | int success = mprotect(mem, size, PROT_EXEC | PROT_READ); 53 | assert(success == 0); 54 | 55 | #ifndef NDEBUG 56 | // Write generated machine code to a temporary file. 57 | // View with: (x86-64) 58 | // objdump -D -b binary -mi386 -Mx86-64 /tmp/jitcode 59 | // Or: (arm) 60 | // arm-linux-gnueabihf-objdump -D -b binary -marm /tmp/jitcode 61 | FILE *f = fopen("/tmp/jitcode", "wb"); 62 | fwrite(ret, size, 1, f); 63 | fclose(f); 64 | #endif 65 | 66 | return ret; 67 | } 68 | 69 | void free_jitcode(void *code) 70 | { 71 | void *mem = (char *) code - sizeof(size_t); 72 | int status = munmap(mem, *(size_t *) mem); 73 | assert(status == 0); 74 | } 75 | -------------------------------------------------------------------------------- /dynasm/COPYRIGHT: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ 3 | 4 | Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 25 | 26 | =============================================================================== 27 | [ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ] 28 | 29 | Copyright (C) 1994-2012 Lua.org, PUC-Rio. 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | 49 | =============================================================================== 50 | [ LuaJIT includes code from dlmalloc, which has this license statement: ] 51 | 52 | This is a version (aka dlmalloc) of malloc/free/realloc written by 53 | Doug Lea and released to the public domain, as explained at 54 | http://creativecommons.org/licenses/publicdomain 55 | 56 | =============================================================================== 57 | -------------------------------------------------------------------------------- /dynasm/README: -------------------------------------------------------------------------------- 1 | URL: http://luajit.org/git/luajit-2.0.git 2 | Version: 1c968d5b631e3bece678dcdce4c14afb9d79d409 3 | License: MIT 4 | License File: COPYRIGHT 5 | Description: 6 | Taken from the larger LuaJIT project, DynASM is a tiny preprocessor and 7 | runtime for generating machine code at runtime. 8 | 9 | Local Modifications: 10 | No modifications. 11 | -------------------------------------------------------------------------------- /dynasm/dasm_arm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM ARM encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "arm" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, 25 | DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, 26 | DASM__MAX 27 | }; 28 | 29 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 30 | #define DASM_MAXSECPOS 25 31 | 32 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 33 | #define DASM_S_OK 0x00000000 34 | #define DASM_S_NOMEM 0x01000000 35 | #define DASM_S_PHASE 0x02000000 36 | #define DASM_S_MATCH_SEC 0x03000000 37 | #define DASM_S_RANGE_I 0x11000000 38 | #define DASM_S_RANGE_SEC 0x12000000 39 | #define DASM_S_RANGE_LG 0x13000000 40 | #define DASM_S_RANGE_PC 0x14000000 41 | #define DASM_S_RANGE_REL 0x15000000 42 | #define DASM_S_UNDEF_LG 0x21000000 43 | #define DASM_S_UNDEF_PC 0x22000000 44 | 45 | /* Macros to convert positions (8 bit section + 24 bit index). */ 46 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 47 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 48 | #define DASM_SEC2POS(sec) ((sec)<<24) 49 | #define DASM_POS2SEC(pos) ((pos)>>24) 50 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 51 | 52 | /* Action list type. */ 53 | typedef const unsigned int *dasm_ActList; 54 | 55 | /* Per-section structure. */ 56 | typedef struct dasm_Section { 57 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 58 | int *buf; /* True buffer pointer. */ 59 | size_t bsize; /* Buffer size in bytes. */ 60 | int pos; /* Biased buffer position. */ 61 | int epos; /* End of biased buffer position - max single put. */ 62 | int ofs; /* Byte offset into section. */ 63 | } dasm_Section; 64 | 65 | /* Core structure holding the DynASM encoding state. */ 66 | struct dasm_State { 67 | size_t psize; /* Allocated size of this structure. */ 68 | dasm_ActList actionlist; /* Current actionlist pointer. */ 69 | int *lglabels; /* Local/global chain/pos ptrs. */ 70 | size_t lgsize; 71 | int *pclabels; /* PC label chains/pos ptrs. */ 72 | size_t pcsize; 73 | void **globals; /* Array of globals (bias -10). */ 74 | dasm_Section *section; /* Pointer to active section. */ 75 | size_t codesize; /* Total size of all code sections. */ 76 | int maxsection; /* 0 <= sectionidx < maxsection. */ 77 | int status; /* Status code. */ 78 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 79 | }; 80 | 81 | /* The size of the core structure depends on the max. number of sections. */ 82 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 83 | 84 | 85 | /* Initialize DynASM state. */ 86 | void dasm_init(Dst_DECL, int maxsection) 87 | { 88 | dasm_State *D; 89 | size_t psz = 0; 90 | int i; 91 | Dst_REF = NULL; 92 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 93 | D = Dst_REF; 94 | D->psize = psz; 95 | D->lglabels = NULL; 96 | D->lgsize = 0; 97 | D->pclabels = NULL; 98 | D->pcsize = 0; 99 | D->globals = NULL; 100 | D->maxsection = maxsection; 101 | for (i = 0; i < maxsection; i++) { 102 | D->sections[i].buf = NULL; /* Need this for pass3. */ 103 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 104 | D->sections[i].bsize = 0; 105 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 106 | } 107 | } 108 | 109 | /* Free DynASM state. */ 110 | void dasm_free(Dst_DECL) 111 | { 112 | dasm_State *D = Dst_REF; 113 | int i; 114 | for (i = 0; i < D->maxsection; i++) 115 | if (D->sections[i].buf) 116 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 117 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 118 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 119 | DASM_M_FREE(Dst, D, D->psize); 120 | } 121 | 122 | /* Setup global label array. Must be called before dasm_setup(). */ 123 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 124 | { 125 | dasm_State *D = Dst_REF; 126 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 127 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 128 | } 129 | 130 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 131 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 132 | { 133 | dasm_State *D = Dst_REF; 134 | size_t osz = D->pcsize; 135 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 136 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 137 | } 138 | 139 | /* Setup encoder. */ 140 | void dasm_setup(Dst_DECL, const void *actionlist) 141 | { 142 | dasm_State *D = Dst_REF; 143 | int i; 144 | D->actionlist = (dasm_ActList)actionlist; 145 | D->status = DASM_S_OK; 146 | D->section = &D->sections[0]; 147 | memset((void *)D->lglabels, 0, D->lgsize); 148 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 149 | for (i = 0; i < D->maxsection; i++) { 150 | D->sections[i].pos = DASM_SEC2POS(i); 151 | D->sections[i].ofs = 0; 152 | } 153 | } 154 | 155 | 156 | #ifdef DASM_CHECKS 157 | #define CK(x, st) \ 158 | do { if (!(x)) { \ 159 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 160 | #define CKPL(kind, st) \ 161 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 162 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 163 | #else 164 | #define CK(x, st) ((void)0) 165 | #define CKPL(kind, st) ((void)0) 166 | #endif 167 | 168 | static int dasm_imm12(unsigned int n) 169 | { 170 | int i; 171 | for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) 172 | if (n <= 255) return (int)(n + (i << 8)); 173 | return -1; 174 | } 175 | 176 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 177 | void dasm_put(Dst_DECL, int start, ...) 178 | { 179 | va_list ap; 180 | dasm_State *D = Dst_REF; 181 | dasm_ActList p = D->actionlist + start; 182 | dasm_Section *sec = D->section; 183 | int pos = sec->pos, ofs = sec->ofs; 184 | int *b; 185 | 186 | if (pos >= sec->epos) { 187 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 188 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 189 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 190 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 191 | } 192 | 193 | b = sec->rbuf; 194 | b[pos++] = start; 195 | 196 | va_start(ap, start); 197 | while (1) { 198 | unsigned int ins = *p++; 199 | unsigned int action = (ins >> 16); 200 | if (action >= DASM__MAX) { 201 | ofs += 4; 202 | } else { 203 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 204 | switch (action) { 205 | case DASM_STOP: goto stop; 206 | case DASM_SECTION: 207 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 208 | D->section = &D->sections[n]; goto stop; 209 | case DASM_ESC: p++; ofs += 4; break; 210 | case DASM_REL_EXT: break; 211 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 212 | case DASM_REL_LG: 213 | n = (ins & 2047) - 10; pl = D->lglabels + n; 214 | /* Bkwd rel or global. */ 215 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 216 | pl += 10; n = *pl; 217 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 218 | goto linkrel; 219 | case DASM_REL_PC: 220 | pl = D->pclabels + n; CKPL(pc, PC); 221 | putrel: 222 | n = *pl; 223 | if (n < 0) { /* Label exists. Get label pos and store it. */ 224 | b[pos] = -n; 225 | } else { 226 | linkrel: 227 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 228 | *pl = pos; 229 | } 230 | pos++; 231 | break; 232 | case DASM_LABEL_LG: 233 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 234 | case DASM_LABEL_PC: 235 | pl = D->pclabels + n; CKPL(pc, PC); 236 | putlabel: 237 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 238 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 239 | } 240 | *pl = -pos; /* Label exists now. */ 241 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 242 | break; 243 | case DASM_IMM: 244 | case DASM_IMM16: 245 | #ifdef DASM_CHECKS 246 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 247 | if ((ins & 0x8000)) 248 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 249 | else 250 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 251 | #endif 252 | b[pos++] = n; 253 | break; 254 | case DASM_IMMV8: 255 | CK((n & 3) == 0, RANGE_I); 256 | n >>= 2; 257 | case DASM_IMML8: 258 | case DASM_IMML12: 259 | CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : 260 | (((-n)>>((ins>>5)&31)) == 0), RANGE_I); 261 | b[pos++] = n; 262 | break; 263 | case DASM_IMM12: 264 | CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); 265 | b[pos++] = n; 266 | break; 267 | } 268 | } 269 | } 270 | stop: 271 | va_end(ap); 272 | sec->pos = pos; 273 | sec->ofs = ofs; 274 | } 275 | #undef CK 276 | 277 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 278 | int dasm_link(Dst_DECL, size_t *szp) 279 | { 280 | dasm_State *D = Dst_REF; 281 | int secnum; 282 | int ofs = 0; 283 | 284 | #ifdef DASM_CHECKS 285 | *szp = 0; 286 | if (D->status != DASM_S_OK) return D->status; 287 | { 288 | int pc; 289 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 290 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 291 | } 292 | #endif 293 | 294 | { /* Handle globals not defined in this translation unit. */ 295 | int idx; 296 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 297 | int n = D->lglabels[idx]; 298 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 299 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 300 | } 301 | } 302 | 303 | /* Combine all code sections. No support for data sections (yet). */ 304 | for (secnum = 0; secnum < D->maxsection; secnum++) { 305 | dasm_Section *sec = D->sections + secnum; 306 | int *b = sec->rbuf; 307 | int pos = DASM_SEC2POS(secnum); 308 | int lastpos = sec->pos; 309 | 310 | while (pos != lastpos) { 311 | dasm_ActList p = D->actionlist + b[pos++]; 312 | while (1) { 313 | unsigned int ins = *p++; 314 | unsigned int action = (ins >> 16); 315 | switch (action) { 316 | case DASM_STOP: case DASM_SECTION: goto stop; 317 | case DASM_ESC: p++; break; 318 | case DASM_REL_EXT: break; 319 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 320 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 321 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 322 | case DASM_IMM: case DASM_IMM12: case DASM_IMM16: 323 | case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; 324 | } 325 | } 326 | stop: (void)0; 327 | } 328 | ofs += sec->ofs; /* Next section starts right after current section. */ 329 | } 330 | 331 | D->codesize = ofs; /* Total size of all code sections */ 332 | *szp = ofs; 333 | return DASM_S_OK; 334 | } 335 | 336 | #ifdef DASM_CHECKS 337 | #define CK(x, st) \ 338 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 339 | #else 340 | #define CK(x, st) ((void)0) 341 | #endif 342 | 343 | /* Pass 3: Encode sections. */ 344 | int dasm_encode(Dst_DECL, void *buffer) 345 | { 346 | dasm_State *D = Dst_REF; 347 | char *base = (char *)buffer; 348 | unsigned int *cp = (unsigned int *)buffer; 349 | int secnum; 350 | 351 | /* Encode all code sections. No support for data sections (yet). */ 352 | for (secnum = 0; secnum < D->maxsection; secnum++) { 353 | dasm_Section *sec = D->sections + secnum; 354 | int *b = sec->buf; 355 | int *endb = sec->rbuf + sec->pos; 356 | 357 | while (b != endb) { 358 | dasm_ActList p = D->actionlist + *b++; 359 | while (1) { 360 | unsigned int ins = *p++; 361 | unsigned int action = (ins >> 16); 362 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 363 | switch (action) { 364 | case DASM_STOP: case DASM_SECTION: goto stop; 365 | case DASM_ESC: *cp++ = *p++; break; 366 | case DASM_REL_EXT: 367 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); 368 | goto patchrel; 369 | case DASM_ALIGN: 370 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; 371 | break; 372 | case DASM_REL_LG: 373 | CK(n >= 0, UNDEF_LG); 374 | case DASM_REL_PC: 375 | CK(n >= 0, UNDEF_PC); 376 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; 377 | patchrel: 378 | if ((ins & 0x800) == 0) { 379 | CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); 380 | cp[-1] |= ((n >> 2) & 0x00ffffff); 381 | } else if ((ins & 0x1000)) { 382 | CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); 383 | goto patchimml8; 384 | } else if ((ins & 0x2000) == 0) { 385 | CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); 386 | goto patchimml; 387 | } else { 388 | CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); 389 | n >>= 2; 390 | goto patchimml; 391 | } 392 | break; 393 | case DASM_LABEL_LG: 394 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 395 | break; 396 | case DASM_LABEL_PC: break; 397 | case DASM_IMM: 398 | cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); 399 | break; 400 | case DASM_IMM12: 401 | cp[-1] |= dasm_imm12((unsigned int)n); 402 | break; 403 | case DASM_IMM16: 404 | cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); 405 | break; 406 | case DASM_IMML8: patchimml8: 407 | cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : 408 | ((-n & 0x0f) | ((-n & 0xf0) << 4)); 409 | break; 410 | case DASM_IMML12: case DASM_IMMV8: patchimml: 411 | cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); 412 | break; 413 | default: *cp++ = ins; break; 414 | } 415 | } 416 | stop: (void)0; 417 | } 418 | } 419 | 420 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 421 | return DASM_S_PHASE; 422 | return DASM_S_OK; 423 | } 424 | #undef CK 425 | 426 | /* Get PC label offset. */ 427 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 428 | { 429 | dasm_State *D = Dst_REF; 430 | if (pc*sizeof(int) < D->pcsize) { 431 | int pos = D->pclabels[pc]; 432 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 433 | if (pos > 0) return -1; /* Undefined. */ 434 | } 435 | return -2; /* Unused or out of range. */ 436 | } 437 | 438 | #ifdef DASM_CHECKS 439 | /* Optional sanity checker to call between isolated encoding steps. */ 440 | int dasm_checkstep(Dst_DECL, int secmatch) 441 | { 442 | dasm_State *D = Dst_REF; 443 | if (D->status == DASM_S_OK) { 444 | int i; 445 | for (i = 1; i <= 9; i++) { 446 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 447 | D->lglabels[i] = 0; 448 | } 449 | } 450 | if (D->status == DASM_S_OK && secmatch >= 0 && 451 | D->section != &D->sections[secmatch]) 452 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 453 | return D->status; 454 | } 455 | #endif 456 | 457 | -------------------------------------------------------------------------------- /dynasm/dasm_arm64.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM ARM64 encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "arm64" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, 25 | DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, 26 | DASM__MAX 27 | }; 28 | 29 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 30 | #define DASM_MAXSECPOS 25 31 | 32 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 33 | #define DASM_S_OK 0x00000000 34 | #define DASM_S_NOMEM 0x01000000 35 | #define DASM_S_PHASE 0x02000000 36 | #define DASM_S_MATCH_SEC 0x03000000 37 | #define DASM_S_RANGE_I 0x11000000 38 | #define DASM_S_RANGE_SEC 0x12000000 39 | #define DASM_S_RANGE_LG 0x13000000 40 | #define DASM_S_RANGE_PC 0x14000000 41 | #define DASM_S_RANGE_REL 0x15000000 42 | #define DASM_S_UNDEF_LG 0x21000000 43 | #define DASM_S_UNDEF_PC 0x22000000 44 | 45 | /* Macros to convert positions (8 bit section + 24 bit index). */ 46 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 47 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 48 | #define DASM_SEC2POS(sec) ((sec)<<24) 49 | #define DASM_POS2SEC(pos) ((pos)>>24) 50 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 51 | 52 | /* Action list type. */ 53 | typedef const unsigned int *dasm_ActList; 54 | 55 | /* Per-section structure. */ 56 | typedef struct dasm_Section { 57 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 58 | int *buf; /* True buffer pointer. */ 59 | size_t bsize; /* Buffer size in bytes. */ 60 | int pos; /* Biased buffer position. */ 61 | int epos; /* End of biased buffer position - max single put. */ 62 | int ofs; /* Byte offset into section. */ 63 | } dasm_Section; 64 | 65 | /* Core structure holding the DynASM encoding state. */ 66 | struct dasm_State { 67 | size_t psize; /* Allocated size of this structure. */ 68 | dasm_ActList actionlist; /* Current actionlist pointer. */ 69 | int *lglabels; /* Local/global chain/pos ptrs. */ 70 | size_t lgsize; 71 | int *pclabels; /* PC label chains/pos ptrs. */ 72 | size_t pcsize; 73 | void **globals; /* Array of globals (bias -10). */ 74 | dasm_Section *section; /* Pointer to active section. */ 75 | size_t codesize; /* Total size of all code sections. */ 76 | int maxsection; /* 0 <= sectionidx < maxsection. */ 77 | int status; /* Status code. */ 78 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 79 | }; 80 | 81 | /* The size of the core structure depends on the max. number of sections. */ 82 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 83 | 84 | 85 | /* Initialize DynASM state. */ 86 | void dasm_init(Dst_DECL, int maxsection) 87 | { 88 | dasm_State *D; 89 | size_t psz = 0; 90 | int i; 91 | Dst_REF = NULL; 92 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 93 | D = Dst_REF; 94 | D->psize = psz; 95 | D->lglabels = NULL; 96 | D->lgsize = 0; 97 | D->pclabels = NULL; 98 | D->pcsize = 0; 99 | D->globals = NULL; 100 | D->maxsection = maxsection; 101 | for (i = 0; i < maxsection; i++) { 102 | D->sections[i].buf = NULL; /* Need this for pass3. */ 103 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 104 | D->sections[i].bsize = 0; 105 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 106 | } 107 | } 108 | 109 | /* Free DynASM state. */ 110 | void dasm_free(Dst_DECL) 111 | { 112 | dasm_State *D = Dst_REF; 113 | int i; 114 | for (i = 0; i < D->maxsection; i++) 115 | if (D->sections[i].buf) 116 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 117 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 118 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 119 | DASM_M_FREE(Dst, D, D->psize); 120 | } 121 | 122 | /* Setup global label array. Must be called before dasm_setup(). */ 123 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 124 | { 125 | dasm_State *D = Dst_REF; 126 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 127 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 128 | } 129 | 130 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 131 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 132 | { 133 | dasm_State *D = Dst_REF; 134 | size_t osz = D->pcsize; 135 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 136 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 137 | } 138 | 139 | /* Setup encoder. */ 140 | void dasm_setup(Dst_DECL, const void *actionlist) 141 | { 142 | dasm_State *D = Dst_REF; 143 | int i; 144 | D->actionlist = (dasm_ActList)actionlist; 145 | D->status = DASM_S_OK; 146 | D->section = &D->sections[0]; 147 | memset((void *)D->lglabels, 0, D->lgsize); 148 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 149 | for (i = 0; i < D->maxsection; i++) { 150 | D->sections[i].pos = DASM_SEC2POS(i); 151 | D->sections[i].ofs = 0; 152 | } 153 | } 154 | 155 | 156 | #ifdef DASM_CHECKS 157 | #define CK(x, st) \ 158 | do { if (!(x)) { \ 159 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 160 | #define CKPL(kind, st) \ 161 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 162 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 163 | #else 164 | #define CK(x, st) ((void)0) 165 | #define CKPL(kind, st) ((void)0) 166 | #endif 167 | 168 | static int dasm_imm12(unsigned int n) 169 | { 170 | if ((n >> 12) == 0) 171 | return n; 172 | else if ((n & 0xff000fff) == 0) 173 | return (n >> 12) | 0x1000; 174 | else 175 | return -1; 176 | } 177 | 178 | static int dasm_ffs(unsigned long long x) 179 | { 180 | int n = -1; 181 | while (x) { x >>= 1; n++; } 182 | return n; 183 | } 184 | 185 | static int dasm_imm13(int lo, int hi) 186 | { 187 | int inv = 0, w = 64, s = 0xfff, xa, xb; 188 | unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; 189 | unsigned long long m = 1ULL, a, b, c; 190 | if (n & 1) { n = ~n; inv = 1; } 191 | a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b); 192 | xa = dasm_ffs(a); xb = dasm_ffs(b); 193 | if (c) { 194 | w = dasm_ffs(c) - xa; 195 | if (w == 32) m = 0x0000000100000001UL; 196 | else if (w == 16) m = 0x0001000100010001UL; 197 | else if (w == 8) m = 0x0101010101010101UL; 198 | else if (w == 4) m = 0x1111111111111111UL; 199 | else if (w == 2) m = 0x5555555555555555UL; 200 | else return -1; 201 | s = (-2*w & 0x3f) - 1; 202 | } else if (!a) { 203 | return -1; 204 | } else if (xb == -1) { 205 | xb = 64; 206 | } 207 | if ((b-a) * m != n) return -1; 208 | if (inv) { 209 | return ((w - xb) << 6) | (s+w+xa-xb); 210 | } else { 211 | return ((w - xa) << 6) | (s+xb-xa); 212 | } 213 | return -1; 214 | } 215 | 216 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 217 | void dasm_put(Dst_DECL, int start, ...) 218 | { 219 | va_list ap; 220 | dasm_State *D = Dst_REF; 221 | dasm_ActList p = D->actionlist + start; 222 | dasm_Section *sec = D->section; 223 | int pos = sec->pos, ofs = sec->ofs; 224 | int *b; 225 | 226 | if (pos >= sec->epos) { 227 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 228 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 229 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 230 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 231 | } 232 | 233 | b = sec->rbuf; 234 | b[pos++] = start; 235 | 236 | va_start(ap, start); 237 | while (1) { 238 | unsigned int ins = *p++; 239 | unsigned int action = (ins >> 16); 240 | if (action >= DASM__MAX) { 241 | ofs += 4; 242 | } else { 243 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 244 | switch (action) { 245 | case DASM_STOP: goto stop; 246 | case DASM_SECTION: 247 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 248 | D->section = &D->sections[n]; goto stop; 249 | case DASM_ESC: p++; ofs += 4; break; 250 | case DASM_REL_EXT: break; 251 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 252 | case DASM_REL_LG: 253 | n = (ins & 2047) - 10; pl = D->lglabels + n; 254 | /* Bkwd rel or global. */ 255 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 256 | pl += 10; n = *pl; 257 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 258 | goto linkrel; 259 | case DASM_REL_PC: 260 | pl = D->pclabels + n; CKPL(pc, PC); 261 | putrel: 262 | n = *pl; 263 | if (n < 0) { /* Label exists. Get label pos and store it. */ 264 | b[pos] = -n; 265 | } else { 266 | linkrel: 267 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 268 | *pl = pos; 269 | } 270 | pos++; 271 | break; 272 | case DASM_LABEL_LG: 273 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 274 | case DASM_LABEL_PC: 275 | pl = D->pclabels + n; CKPL(pc, PC); 276 | putlabel: 277 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 278 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 279 | } 280 | *pl = -pos; /* Label exists now. */ 281 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 282 | break; 283 | case DASM_IMM: 284 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 285 | n >>= ((ins>>10)&31); 286 | #ifdef DASM_CHECKS 287 | if ((ins & 0x8000)) 288 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 289 | else 290 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 291 | #endif 292 | b[pos++] = n; 293 | break; 294 | case DASM_IMM6: 295 | CK((n >> 6) == 0, RANGE_I); 296 | b[pos++] = n; 297 | break; 298 | case DASM_IMM12: 299 | CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); 300 | b[pos++] = n; 301 | break; 302 | case DASM_IMM13W: 303 | CK(dasm_imm13(n, n) != -1, RANGE_I); 304 | b[pos++] = n; 305 | break; 306 | case DASM_IMM13X: { 307 | int m = va_arg(ap, int); 308 | CK(dasm_imm13(n, m) != -1, RANGE_I); 309 | b[pos++] = n; 310 | b[pos++] = m; 311 | break; 312 | } 313 | case DASM_IMML: { 314 | #ifdef DASM_CHECKS 315 | int scale = (p[-2] >> 30); 316 | CK((!(n & ((1<>scale) < 4096) || 317 | (unsigned int)(n+256) < 512, RANGE_I); 318 | #endif 319 | b[pos++] = n; 320 | break; 321 | } 322 | } 323 | } 324 | } 325 | stop: 326 | va_end(ap); 327 | sec->pos = pos; 328 | sec->ofs = ofs; 329 | } 330 | #undef CK 331 | 332 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 333 | int dasm_link(Dst_DECL, size_t *szp) 334 | { 335 | dasm_State *D = Dst_REF; 336 | int secnum; 337 | int ofs = 0; 338 | 339 | #ifdef DASM_CHECKS 340 | *szp = 0; 341 | if (D->status != DASM_S_OK) return D->status; 342 | { 343 | int pc; 344 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 345 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 346 | } 347 | #endif 348 | 349 | { /* Handle globals not defined in this translation unit. */ 350 | int idx; 351 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 352 | int n = D->lglabels[idx]; 353 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 354 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 355 | } 356 | } 357 | 358 | /* Combine all code sections. No support for data sections (yet). */ 359 | for (secnum = 0; secnum < D->maxsection; secnum++) { 360 | dasm_Section *sec = D->sections + secnum; 361 | int *b = sec->rbuf; 362 | int pos = DASM_SEC2POS(secnum); 363 | int lastpos = sec->pos; 364 | 365 | while (pos != lastpos) { 366 | dasm_ActList p = D->actionlist + b[pos++]; 367 | while (1) { 368 | unsigned int ins = *p++; 369 | unsigned int action = (ins >> 16); 370 | switch (action) { 371 | case DASM_STOP: case DASM_SECTION: goto stop; 372 | case DASM_ESC: p++; break; 373 | case DASM_REL_EXT: break; 374 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 375 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 376 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 377 | case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: 378 | case DASM_IMML: pos++; break; 379 | case DASM_IMM13X: pos += 2; break; 380 | } 381 | } 382 | stop: (void)0; 383 | } 384 | ofs += sec->ofs; /* Next section starts right after current section. */ 385 | } 386 | 387 | D->codesize = ofs; /* Total size of all code sections */ 388 | *szp = ofs; 389 | return DASM_S_OK; 390 | } 391 | 392 | #ifdef DASM_CHECKS 393 | #define CK(x, st) \ 394 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 395 | #else 396 | #define CK(x, st) ((void)0) 397 | #endif 398 | 399 | /* Pass 3: Encode sections. */ 400 | int dasm_encode(Dst_DECL, void *buffer) 401 | { 402 | dasm_State *D = Dst_REF; 403 | char *base = (char *)buffer; 404 | unsigned int *cp = (unsigned int *)buffer; 405 | int secnum; 406 | 407 | /* Encode all code sections. No support for data sections (yet). */ 408 | for (secnum = 0; secnum < D->maxsection; secnum++) { 409 | dasm_Section *sec = D->sections + secnum; 410 | int *b = sec->buf; 411 | int *endb = sec->rbuf + sec->pos; 412 | 413 | while (b != endb) { 414 | dasm_ActList p = D->actionlist + *b++; 415 | while (1) { 416 | unsigned int ins = *p++; 417 | unsigned int action = (ins >> 16); 418 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 419 | switch (action) { 420 | case DASM_STOP: case DASM_SECTION: goto stop; 421 | case DASM_ESC: *cp++ = *p++; break; 422 | case DASM_REL_EXT: 423 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); 424 | goto patchrel; 425 | case DASM_ALIGN: 426 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; 427 | break; 428 | case DASM_REL_LG: 429 | CK(n >= 0, UNDEF_LG); 430 | case DASM_REL_PC: 431 | CK(n >= 0, UNDEF_PC); 432 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; 433 | patchrel: 434 | if (!(ins & 0xf800)) { /* B, BL */ 435 | CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL); 436 | cp[-1] |= ((n >> 2) & 0x03ffffff); 437 | } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ 438 | CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL); 439 | cp[-1] |= ((n << 3) & 0x00ffffe0); 440 | } else if ((ins & 0x3000) == 0x2000) { /* ADR */ 441 | CK(((n+0x00100000) >> 21) == 0, RANGE_REL); 442 | cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); 443 | } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ 444 | cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); 445 | } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ 446 | CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL); 447 | cp[-1] |= ((n << 3) & 0x0007ffe0); 448 | } 449 | break; 450 | case DASM_LABEL_LG: 451 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 452 | break; 453 | case DASM_LABEL_PC: break; 454 | case DASM_IMM: 455 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); 456 | break; 457 | case DASM_IMM6: 458 | cp[-1] |= ((n&31) << 19) | ((n&32) << 26); 459 | break; 460 | case DASM_IMM12: 461 | cp[-1] |= (dasm_imm12((unsigned int)n) << 10); 462 | break; 463 | case DASM_IMM13W: 464 | cp[-1] |= (dasm_imm13(n, n) << 10); 465 | break; 466 | case DASM_IMM13X: 467 | cp[-1] |= (dasm_imm13(n, *b++) << 10); 468 | break; 469 | case DASM_IMML: { 470 | int scale = (p[-2] >> 30); 471 | cp[-1] |= (!(n & ((1<>scale) < 4096) ? 472 | ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); 473 | break; 474 | } 475 | default: *cp++ = ins; break; 476 | } 477 | } 478 | stop: (void)0; 479 | } 480 | } 481 | 482 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 483 | return DASM_S_PHASE; 484 | return DASM_S_OK; 485 | } 486 | #undef CK 487 | 488 | /* Get PC label offset. */ 489 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 490 | { 491 | dasm_State *D = Dst_REF; 492 | if (pc*sizeof(int) < D->pcsize) { 493 | int pos = D->pclabels[pc]; 494 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 495 | if (pos > 0) return -1; /* Undefined. */ 496 | } 497 | return -2; /* Unused or out of range. */ 498 | } 499 | 500 | #ifdef DASM_CHECKS 501 | /* Optional sanity checker to call between isolated encoding steps. */ 502 | int dasm_checkstep(Dst_DECL, int secmatch) 503 | { 504 | dasm_State *D = Dst_REF; 505 | if (D->status == DASM_S_OK) { 506 | int i; 507 | for (i = 1; i <= 9; i++) { 508 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 509 | D->lglabels[i] = 0; 510 | } 511 | } 512 | if (D->status == DASM_S_OK && secmatch >= 0 && 513 | D->section != &D->sections[secmatch]) 514 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 515 | return D->status; 516 | } 517 | #endif 518 | 519 | -------------------------------------------------------------------------------- /dynasm/dasm_mips.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM MIPS encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "mips" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, 25 | DASM__MAX 26 | }; 27 | 28 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 29 | #define DASM_MAXSECPOS 25 30 | 31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 32 | #define DASM_S_OK 0x00000000 33 | #define DASM_S_NOMEM 0x01000000 34 | #define DASM_S_PHASE 0x02000000 35 | #define DASM_S_MATCH_SEC 0x03000000 36 | #define DASM_S_RANGE_I 0x11000000 37 | #define DASM_S_RANGE_SEC 0x12000000 38 | #define DASM_S_RANGE_LG 0x13000000 39 | #define DASM_S_RANGE_PC 0x14000000 40 | #define DASM_S_RANGE_REL 0x15000000 41 | #define DASM_S_UNDEF_LG 0x21000000 42 | #define DASM_S_UNDEF_PC 0x22000000 43 | 44 | /* Macros to convert positions (8 bit section + 24 bit index). */ 45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 47 | #define DASM_SEC2POS(sec) ((sec)<<24) 48 | #define DASM_POS2SEC(pos) ((pos)>>24) 49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 50 | 51 | /* Action list type. */ 52 | typedef const unsigned int *dasm_ActList; 53 | 54 | /* Per-section structure. */ 55 | typedef struct dasm_Section { 56 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 57 | int *buf; /* True buffer pointer. */ 58 | size_t bsize; /* Buffer size in bytes. */ 59 | int pos; /* Biased buffer position. */ 60 | int epos; /* End of biased buffer position - max single put. */ 61 | int ofs; /* Byte offset into section. */ 62 | } dasm_Section; 63 | 64 | /* Core structure holding the DynASM encoding state. */ 65 | struct dasm_State { 66 | size_t psize; /* Allocated size of this structure. */ 67 | dasm_ActList actionlist; /* Current actionlist pointer. */ 68 | int *lglabels; /* Local/global chain/pos ptrs. */ 69 | size_t lgsize; 70 | int *pclabels; /* PC label chains/pos ptrs. */ 71 | size_t pcsize; 72 | void **globals; /* Array of globals (bias -10). */ 73 | dasm_Section *section; /* Pointer to active section. */ 74 | size_t codesize; /* Total size of all code sections. */ 75 | int maxsection; /* 0 <= sectionidx < maxsection. */ 76 | int status; /* Status code. */ 77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 78 | }; 79 | 80 | /* The size of the core structure depends on the max. number of sections. */ 81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 82 | 83 | 84 | /* Initialize DynASM state. */ 85 | void dasm_init(Dst_DECL, int maxsection) 86 | { 87 | dasm_State *D; 88 | size_t psz = 0; 89 | int i; 90 | Dst_REF = NULL; 91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 92 | D = Dst_REF; 93 | D->psize = psz; 94 | D->lglabels = NULL; 95 | D->lgsize = 0; 96 | D->pclabels = NULL; 97 | D->pcsize = 0; 98 | D->globals = NULL; 99 | D->maxsection = maxsection; 100 | for (i = 0; i < maxsection; i++) { 101 | D->sections[i].buf = NULL; /* Need this for pass3. */ 102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 103 | D->sections[i].bsize = 0; 104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 105 | } 106 | } 107 | 108 | /* Free DynASM state. */ 109 | void dasm_free(Dst_DECL) 110 | { 111 | dasm_State *D = Dst_REF; 112 | int i; 113 | for (i = 0; i < D->maxsection; i++) 114 | if (D->sections[i].buf) 115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 118 | DASM_M_FREE(Dst, D, D->psize); 119 | } 120 | 121 | /* Setup global label array. Must be called before dasm_setup(). */ 122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 123 | { 124 | dasm_State *D = Dst_REF; 125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 127 | } 128 | 129 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 130 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 131 | { 132 | dasm_State *D = Dst_REF; 133 | size_t osz = D->pcsize; 134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 136 | } 137 | 138 | /* Setup encoder. */ 139 | void dasm_setup(Dst_DECL, const void *actionlist) 140 | { 141 | dasm_State *D = Dst_REF; 142 | int i; 143 | D->actionlist = (dasm_ActList)actionlist; 144 | D->status = DASM_S_OK; 145 | D->section = &D->sections[0]; 146 | memset((void *)D->lglabels, 0, D->lgsize); 147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 148 | for (i = 0; i < D->maxsection; i++) { 149 | D->sections[i].pos = DASM_SEC2POS(i); 150 | D->sections[i].ofs = 0; 151 | } 152 | } 153 | 154 | 155 | #ifdef DASM_CHECKS 156 | #define CK(x, st) \ 157 | do { if (!(x)) { \ 158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 159 | #define CKPL(kind, st) \ 160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 162 | #else 163 | #define CK(x, st) ((void)0) 164 | #define CKPL(kind, st) ((void)0) 165 | #endif 166 | 167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 168 | void dasm_put(Dst_DECL, int start, ...) 169 | { 170 | va_list ap; 171 | dasm_State *D = Dst_REF; 172 | dasm_ActList p = D->actionlist + start; 173 | dasm_Section *sec = D->section; 174 | int pos = sec->pos, ofs = sec->ofs; 175 | int *b; 176 | 177 | if (pos >= sec->epos) { 178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 182 | } 183 | 184 | b = sec->rbuf; 185 | b[pos++] = start; 186 | 187 | va_start(ap, start); 188 | while (1) { 189 | unsigned int ins = *p++; 190 | unsigned int action = (ins >> 16) - 0xff00; 191 | if (action >= DASM__MAX) { 192 | ofs += 4; 193 | } else { 194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 195 | switch (action) { 196 | case DASM_STOP: goto stop; 197 | case DASM_SECTION: 198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 199 | D->section = &D->sections[n]; goto stop; 200 | case DASM_ESC: p++; ofs += 4; break; 201 | case DASM_REL_EXT: break; 202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 203 | case DASM_REL_LG: 204 | n = (ins & 2047) - 10; pl = D->lglabels + n; 205 | /* Bkwd rel or global. */ 206 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 207 | pl += 10; n = *pl; 208 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 209 | goto linkrel; 210 | case DASM_REL_PC: 211 | pl = D->pclabels + n; CKPL(pc, PC); 212 | putrel: 213 | n = *pl; 214 | if (n < 0) { /* Label exists. Get label pos and store it. */ 215 | b[pos] = -n; 216 | } else { 217 | linkrel: 218 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 219 | *pl = pos; 220 | } 221 | pos++; 222 | break; 223 | case DASM_LABEL_LG: 224 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 225 | case DASM_LABEL_PC: 226 | pl = D->pclabels + n; CKPL(pc, PC); 227 | putlabel: 228 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 229 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 230 | } 231 | *pl = -pos; /* Label exists now. */ 232 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 233 | break; 234 | case DASM_IMM: 235 | #ifdef DASM_CHECKS 236 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 237 | #endif 238 | n >>= ((ins>>10)&31); 239 | #ifdef DASM_CHECKS 240 | if (ins & 0x8000) 241 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 242 | else 243 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 244 | #endif 245 | b[pos++] = n; 246 | break; 247 | } 248 | } 249 | } 250 | stop: 251 | va_end(ap); 252 | sec->pos = pos; 253 | sec->ofs = ofs; 254 | } 255 | #undef CK 256 | 257 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 258 | int dasm_link(Dst_DECL, size_t *szp) 259 | { 260 | dasm_State *D = Dst_REF; 261 | int secnum; 262 | int ofs = 0; 263 | 264 | #ifdef DASM_CHECKS 265 | *szp = 0; 266 | if (D->status != DASM_S_OK) return D->status; 267 | { 268 | int pc; 269 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 270 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 271 | } 272 | #endif 273 | 274 | { /* Handle globals not defined in this translation unit. */ 275 | int idx; 276 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 277 | int n = D->lglabels[idx]; 278 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 279 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 280 | } 281 | } 282 | 283 | /* Combine all code sections. No support for data sections (yet). */ 284 | for (secnum = 0; secnum < D->maxsection; secnum++) { 285 | dasm_Section *sec = D->sections + secnum; 286 | int *b = sec->rbuf; 287 | int pos = DASM_SEC2POS(secnum); 288 | int lastpos = sec->pos; 289 | 290 | while (pos != lastpos) { 291 | dasm_ActList p = D->actionlist + b[pos++]; 292 | while (1) { 293 | unsigned int ins = *p++; 294 | unsigned int action = (ins >> 16) - 0xff00; 295 | switch (action) { 296 | case DASM_STOP: case DASM_SECTION: goto stop; 297 | case DASM_ESC: p++; break; 298 | case DASM_REL_EXT: break; 299 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 300 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 301 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 302 | case DASM_IMM: pos++; break; 303 | } 304 | } 305 | stop: (void)0; 306 | } 307 | ofs += sec->ofs; /* Next section starts right after current section. */ 308 | } 309 | 310 | D->codesize = ofs; /* Total size of all code sections */ 311 | *szp = ofs; 312 | return DASM_S_OK; 313 | } 314 | 315 | #ifdef DASM_CHECKS 316 | #define CK(x, st) \ 317 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 318 | #else 319 | #define CK(x, st) ((void)0) 320 | #endif 321 | 322 | /* Pass 3: Encode sections. */ 323 | int dasm_encode(Dst_DECL, void *buffer) 324 | { 325 | dasm_State *D = Dst_REF; 326 | char *base = (char *)buffer; 327 | unsigned int *cp = (unsigned int *)buffer; 328 | int secnum; 329 | 330 | /* Encode all code sections. No support for data sections (yet). */ 331 | for (secnum = 0; secnum < D->maxsection; secnum++) { 332 | dasm_Section *sec = D->sections + secnum; 333 | int *b = sec->buf; 334 | int *endb = sec->rbuf + sec->pos; 335 | 336 | while (b != endb) { 337 | dasm_ActList p = D->actionlist + *b++; 338 | while (1) { 339 | unsigned int ins = *p++; 340 | unsigned int action = (ins >> 16) - 0xff00; 341 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 342 | switch (action) { 343 | case DASM_STOP: case DASM_SECTION: goto stop; 344 | case DASM_ESC: *cp++ = *p++; break; 345 | case DASM_REL_EXT: 346 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); 347 | goto patchrel; 348 | case DASM_ALIGN: 349 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; 350 | break; 351 | case DASM_REL_LG: 352 | CK(n >= 0, UNDEF_LG); 353 | case DASM_REL_PC: 354 | CK(n >= 0, UNDEF_PC); 355 | n = *DASM_POS2PTR(D, n); 356 | if (ins & 2048) 357 | n = n - (int)((char *)cp - base); 358 | else 359 | n = (n + (int)base) & 0x0fffffff; 360 | patchrel: 361 | CK((n & 3) == 0 && 362 | ((n + ((ins & 2048) ? 0x00020000 : 0)) >> 363 | ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); 364 | cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); 365 | break; 366 | case DASM_LABEL_LG: 367 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 368 | break; 369 | case DASM_LABEL_PC: break; 370 | case DASM_IMM: 371 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); 372 | break; 373 | default: *cp++ = ins; break; 374 | } 375 | } 376 | stop: (void)0; 377 | } 378 | } 379 | 380 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 381 | return DASM_S_PHASE; 382 | return DASM_S_OK; 383 | } 384 | #undef CK 385 | 386 | /* Get PC label offset. */ 387 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 388 | { 389 | dasm_State *D = Dst_REF; 390 | if (pc*sizeof(int) < D->pcsize) { 391 | int pos = D->pclabels[pc]; 392 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 393 | if (pos > 0) return -1; /* Undefined. */ 394 | } 395 | return -2; /* Unused or out of range. */ 396 | } 397 | 398 | #ifdef DASM_CHECKS 399 | /* Optional sanity checker to call between isolated encoding steps. */ 400 | int dasm_checkstep(Dst_DECL, int secmatch) 401 | { 402 | dasm_State *D = Dst_REF; 403 | if (D->status == DASM_S_OK) { 404 | int i; 405 | for (i = 1; i <= 9; i++) { 406 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 407 | D->lglabels[i] = 0; 408 | } 409 | } 410 | if (D->status == DASM_S_OK && secmatch >= 0 && 411 | D->section != &D->sections[secmatch]) 412 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 413 | return D->status; 414 | } 415 | #endif 416 | 417 | -------------------------------------------------------------------------------- /dynasm/dasm_mips.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM MIPS module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | 8 | -- Module information: 9 | local _info = { 10 | arch = "mips", 11 | description = "DynASM MIPS module", 12 | version = "1.3.0", 13 | vernum = 10300, 14 | release = "2012-01-23", 15 | author = "Mike Pall", 16 | license = "MIT", 17 | } 18 | 19 | -- Exported glue functions for the arch-specific module. 20 | local _M = { _info = _info } 21 | 22 | -- Cache library functions. 23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs 24 | local assert, setmetatable = assert, setmetatable 25 | local _s = string 26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char 27 | local match, gmatch = _s.match, _s.gmatch 28 | local concat, sort = table.concat, table.sort 29 | local bit = bit or require("bit") 30 | local band, shl, sar, tohex = bit.band, bit.lshift, bit.arshift, bit.tohex 31 | 32 | -- Inherited tables and callbacks. 33 | local g_opt, g_arch 34 | local wline, werror, wfatal, wwarn 35 | 36 | -- Action name list. 37 | -- CHECK: Keep this in sync with the C code! 38 | local action_names = { 39 | "STOP", "SECTION", "ESC", "REL_EXT", 40 | "ALIGN", "REL_LG", "LABEL_LG", 41 | "REL_PC", "LABEL_PC", "IMM", 42 | } 43 | 44 | -- Maximum number of section buffer positions for dasm_put(). 45 | -- CHECK: Keep this in sync with the C code! 46 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. 47 | 48 | -- Action name -> action number. 49 | local map_action = {} 50 | for n,name in ipairs(action_names) do 51 | map_action[name] = n-1 52 | end 53 | 54 | -- Action list buffer. 55 | local actlist = {} 56 | 57 | -- Argument list for next dasm_put(). Start with offset 0 into action list. 58 | local actargs = { 0 } 59 | 60 | -- Current number of section buffer positions for dasm_put(). 61 | local secpos = 1 62 | 63 | ------------------------------------------------------------------------------ 64 | 65 | -- Dump action names and numbers. 66 | local function dumpactions(out) 67 | out:write("DynASM encoding engine action codes:\n") 68 | for n,name in ipairs(action_names) do 69 | local num = map_action[name] 70 | out:write(format(" %-10s %02X %d\n", name, num, num)) 71 | end 72 | out:write("\n") 73 | end 74 | 75 | -- Write action list buffer as a huge static C array. 76 | local function writeactions(out, name) 77 | local nn = #actlist 78 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end 79 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") 80 | for i = 1,nn-1 do 81 | assert(out:write("0x", tohex(actlist[i]), ",\n")) 82 | end 83 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) 84 | end 85 | 86 | ------------------------------------------------------------------------------ 87 | 88 | -- Add word to action list. 89 | local function wputxw(n) 90 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 91 | actlist[#actlist+1] = n 92 | end 93 | 94 | -- Add action to list with optional arg. Advance buffer pos, too. 95 | local function waction(action, val, a, num) 96 | local w = assert(map_action[action], "bad action name `"..action.."'") 97 | wputxw(0xff000000 + w * 0x10000 + (val or 0)) 98 | if a then actargs[#actargs+1] = a end 99 | if a or num then secpos = secpos + (num or 1) end 100 | end 101 | 102 | -- Flush action list (intervening C code or buffer pos overflow). 103 | local function wflush(term) 104 | if #actlist == actargs[1] then return end -- Nothing to flush. 105 | if not term then waction("STOP") end -- Terminate action list. 106 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) 107 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). 108 | secpos = 1 -- The actionlist offset occupies a buffer position, too. 109 | end 110 | 111 | -- Put escaped word. 112 | local function wputw(n) 113 | if n >= 0xff000000 then waction("ESC") end 114 | wputxw(n) 115 | end 116 | 117 | -- Reserve position for word. 118 | local function wpos() 119 | local pos = #actlist+1 120 | actlist[pos] = "" 121 | return pos 122 | end 123 | 124 | -- Store word to reserved position. 125 | local function wputpos(pos, n) 126 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") 127 | actlist[pos] = n 128 | end 129 | 130 | ------------------------------------------------------------------------------ 131 | 132 | -- Global label name -> global label number. With auto assignment on 1st use. 133 | local next_global = 20 134 | local map_global = setmetatable({}, { __index = function(t, name) 135 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end 136 | local n = next_global 137 | if n > 2047 then werror("too many global labels") end 138 | next_global = n + 1 139 | t[name] = n 140 | return n 141 | end}) 142 | 143 | -- Dump global labels. 144 | local function dumpglobals(out, lvl) 145 | local t = {} 146 | for name, n in pairs(map_global) do t[n] = name end 147 | out:write("Global labels:\n") 148 | for i=20,next_global-1 do 149 | out:write(format(" %s\n", t[i])) 150 | end 151 | out:write("\n") 152 | end 153 | 154 | -- Write global label enum. 155 | local function writeglobals(out, prefix) 156 | local t = {} 157 | for name, n in pairs(map_global) do t[n] = name end 158 | out:write("enum {\n") 159 | for i=20,next_global-1 do 160 | out:write(" ", prefix, t[i], ",\n") 161 | end 162 | out:write(" ", prefix, "_MAX\n};\n") 163 | end 164 | 165 | -- Write global label names. 166 | local function writeglobalnames(out, name) 167 | local t = {} 168 | for name, n in pairs(map_global) do t[n] = name end 169 | out:write("static const char *const ", name, "[] = {\n") 170 | for i=20,next_global-1 do 171 | out:write(" \"", t[i], "\",\n") 172 | end 173 | out:write(" (const char *)0\n};\n") 174 | end 175 | 176 | ------------------------------------------------------------------------------ 177 | 178 | -- Extern label name -> extern label number. With auto assignment on 1st use. 179 | local next_extern = 0 180 | local map_extern_ = {} 181 | local map_extern = setmetatable({}, { __index = function(t, name) 182 | -- No restrictions on the name for now. 183 | local n = next_extern 184 | if n > 2047 then werror("too many extern labels") end 185 | next_extern = n + 1 186 | t[name] = n 187 | map_extern_[n] = name 188 | return n 189 | end}) 190 | 191 | -- Dump extern labels. 192 | local function dumpexterns(out, lvl) 193 | out:write("Extern labels:\n") 194 | for i=0,next_extern-1 do 195 | out:write(format(" %s\n", map_extern_[i])) 196 | end 197 | out:write("\n") 198 | end 199 | 200 | -- Write extern label names. 201 | local function writeexternnames(out, name) 202 | out:write("static const char *const ", name, "[] = {\n") 203 | for i=0,next_extern-1 do 204 | out:write(" \"", map_extern_[i], "\",\n") 205 | end 206 | out:write(" (const char *)0\n};\n") 207 | end 208 | 209 | ------------------------------------------------------------------------------ 210 | 211 | -- Arch-specific maps. 212 | local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. 213 | 214 | local map_type = {} -- Type name -> { ctype, reg } 215 | local ctypenum = 0 -- Type number (for Dt... macros). 216 | 217 | -- Reverse defines for registers. 218 | function _M.revdef(s) 219 | if s == "r29" then return "sp" 220 | elseif s == "r31" then return "ra" end 221 | return s 222 | end 223 | 224 | ------------------------------------------------------------------------------ 225 | 226 | -- Template strings for MIPS instructions. 227 | local map_op = { 228 | -- First-level opcodes. 229 | j_1 = "08000000J", 230 | jal_1 = "0c000000J", 231 | b_1 = "10000000B", 232 | beqz_2 = "10000000SB", 233 | beq_3 = "10000000STB", 234 | bnez_2 = "14000000SB", 235 | bne_3 = "14000000STB", 236 | blez_2 = "18000000SB", 237 | bgtz_2 = "1c000000SB", 238 | addi_3 = "20000000TSI", 239 | li_2 = "24000000TI", 240 | addiu_3 = "24000000TSI", 241 | slti_3 = "28000000TSI", 242 | sltiu_3 = "2c000000TSI", 243 | andi_3 = "30000000TSU", 244 | lu_2 = "34000000TU", 245 | ori_3 = "34000000TSU", 246 | xori_3 = "38000000TSU", 247 | lui_2 = "3c000000TU", 248 | beqzl_2 = "50000000SB", 249 | beql_3 = "50000000STB", 250 | bnezl_2 = "54000000SB", 251 | bnel_3 = "54000000STB", 252 | blezl_2 = "58000000SB", 253 | bgtzl_2 = "5c000000SB", 254 | lb_2 = "80000000TO", 255 | lh_2 = "84000000TO", 256 | lwl_2 = "88000000TO", 257 | lw_2 = "8c000000TO", 258 | lbu_2 = "90000000TO", 259 | lhu_2 = "94000000TO", 260 | lwr_2 = "98000000TO", 261 | sb_2 = "a0000000TO", 262 | sh_2 = "a4000000TO", 263 | swl_2 = "a8000000TO", 264 | sw_2 = "ac000000TO", 265 | swr_2 = "b8000000TO", 266 | cache_2 = "bc000000NO", 267 | ll_2 = "c0000000TO", 268 | lwc1_2 = "c4000000HO", 269 | pref_2 = "cc000000NO", 270 | ldc1_2 = "d4000000HO", 271 | sc_2 = "e0000000TO", 272 | swc1_2 = "e4000000HO", 273 | sdc1_2 = "f4000000HO", 274 | 275 | -- Opcode SPECIAL. 276 | nop_0 = "00000000", 277 | sll_3 = "00000000DTA", 278 | movf_2 = "00000001DS", 279 | movf_3 = "00000001DSC", 280 | movt_2 = "00010001DS", 281 | movt_3 = "00010001DSC", 282 | srl_3 = "00000002DTA", 283 | rotr_3 = "00200002DTA", 284 | sra_3 = "00000003DTA", 285 | sllv_3 = "00000004DTS", 286 | srlv_3 = "00000006DTS", 287 | rotrv_3 = "00000046DTS", 288 | srav_3 = "00000007DTS", 289 | jr_1 = "00000008S", 290 | jalr_1 = "0000f809S", 291 | jalr_2 = "00000009DS", 292 | movz_3 = "0000000aDST", 293 | movn_3 = "0000000bDST", 294 | syscall_0 = "0000000c", 295 | syscall_1 = "0000000cY", 296 | break_0 = "0000000d", 297 | break_1 = "0000000dY", 298 | sync_0 = "0000000f", 299 | mfhi_1 = "00000010D", 300 | mthi_1 = "00000011S", 301 | mflo_1 = "00000012D", 302 | mtlo_1 = "00000013S", 303 | mult_2 = "00000018ST", 304 | multu_2 = "00000019ST", 305 | div_2 = "0000001aST", 306 | divu_2 = "0000001bST", 307 | add_3 = "00000020DST", 308 | move_2 = "00000021DS", 309 | addu_3 = "00000021DST", 310 | sub_3 = "00000022DST", 311 | negu_2 = "00000023DT", 312 | subu_3 = "00000023DST", 313 | and_3 = "00000024DST", 314 | or_3 = "00000025DST", 315 | xor_3 = "00000026DST", 316 | not_2 = "00000027DS", 317 | nor_3 = "00000027DST", 318 | slt_3 = "0000002aDST", 319 | sltu_3 = "0000002bDST", 320 | tge_2 = "00000030ST", 321 | tge_3 = "00000030STZ", 322 | tgeu_2 = "00000031ST", 323 | tgeu_3 = "00000031STZ", 324 | tlt_2 = "00000032ST", 325 | tlt_3 = "00000032STZ", 326 | tltu_2 = "00000033ST", 327 | tltu_3 = "00000033STZ", 328 | teq_2 = "00000034ST", 329 | teq_3 = "00000034STZ", 330 | tne_2 = "00000036ST", 331 | tne_3 = "00000036STZ", 332 | 333 | -- Opcode REGIMM. 334 | bltz_2 = "04000000SB", 335 | bgez_2 = "04010000SB", 336 | bltzl_2 = "04020000SB", 337 | bgezl_2 = "04030000SB", 338 | tgei_2 = "04080000SI", 339 | tgeiu_2 = "04090000SI", 340 | tlti_2 = "040a0000SI", 341 | tltiu_2 = "040b0000SI", 342 | teqi_2 = "040c0000SI", 343 | tnei_2 = "040e0000SI", 344 | bltzal_2 = "04100000SB", 345 | bal_1 = "04110000B", 346 | bgezal_2 = "04110000SB", 347 | bltzall_2 = "04120000SB", 348 | bgezall_2 = "04130000SB", 349 | synci_1 = "041f0000O", 350 | 351 | -- Opcode SPECIAL2. 352 | madd_2 = "70000000ST", 353 | maddu_2 = "70000001ST", 354 | mul_3 = "70000002DST", 355 | msub_2 = "70000004ST", 356 | msubu_2 = "70000005ST", 357 | clz_2 = "70000020DS=", 358 | clo_2 = "70000021DS=", 359 | sdbbp_0 = "7000003f", 360 | sdbbp_1 = "7000003fY", 361 | 362 | -- Opcode SPECIAL3. 363 | ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 364 | ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 365 | wsbh_2 = "7c0000a0DT", 366 | seb_2 = "7c000420DT", 367 | seh_2 = "7c000620DT", 368 | rdhwr_2 = "7c00003bTD", 369 | 370 | -- Opcode COP0. 371 | mfc0_2 = "40000000TD", 372 | mfc0_3 = "40000000TDW", 373 | mtc0_2 = "40800000TD", 374 | mtc0_3 = "40800000TDW", 375 | rdpgpr_2 = "41400000DT", 376 | di_0 = "41606000", 377 | di_1 = "41606000T", 378 | ei_0 = "41606020", 379 | ei_1 = "41606020T", 380 | wrpgpr_2 = "41c00000DT", 381 | tlbr_0 = "42000001", 382 | tlbwi_0 = "42000002", 383 | tlbwr_0 = "42000006", 384 | tlbp_0 = "42000008", 385 | eret_0 = "42000018", 386 | deret_0 = "4200001f", 387 | wait_0 = "42000020", 388 | 389 | -- Opcode COP1. 390 | mfc1_2 = "44000000TG", 391 | cfc1_2 = "44400000TG", 392 | mfhc1_2 = "44600000TG", 393 | mtc1_2 = "44800000TG", 394 | ctc1_2 = "44c00000TG", 395 | mthc1_2 = "44e00000TG", 396 | 397 | bc1f_1 = "45000000B", 398 | bc1f_2 = "45000000CB", 399 | bc1t_1 = "45010000B", 400 | bc1t_2 = "45010000CB", 401 | bc1fl_1 = "45020000B", 402 | bc1fl_2 = "45020000CB", 403 | bc1tl_1 = "45030000B", 404 | bc1tl_2 = "45030000CB", 405 | 406 | ["add.s_3"] = "46000000FGH", 407 | ["sub.s_3"] = "46000001FGH", 408 | ["mul.s_3"] = "46000002FGH", 409 | ["div.s_3"] = "46000003FGH", 410 | ["sqrt.s_2"] = "46000004FG", 411 | ["abs.s_2"] = "46000005FG", 412 | ["mov.s_2"] = "46000006FG", 413 | ["neg.s_2"] = "46000007FG", 414 | ["round.l.s_2"] = "46000008FG", 415 | ["trunc.l.s_2"] = "46000009FG", 416 | ["ceil.l.s_2"] = "4600000aFG", 417 | ["floor.l.s_2"] = "4600000bFG", 418 | ["round.w.s_2"] = "4600000cFG", 419 | ["trunc.w.s_2"] = "4600000dFG", 420 | ["ceil.w.s_2"] = "4600000eFG", 421 | ["floor.w.s_2"] = "4600000fFG", 422 | ["movf.s_2"] = "46000011FG", 423 | ["movf.s_3"] = "46000011FGC", 424 | ["movt.s_2"] = "46010011FG", 425 | ["movt.s_3"] = "46010011FGC", 426 | ["movz.s_3"] = "46000012FGT", 427 | ["movn.s_3"] = "46000013FGT", 428 | ["recip.s_2"] = "46000015FG", 429 | ["rsqrt.s_2"] = "46000016FG", 430 | ["cvt.d.s_2"] = "46000021FG", 431 | ["cvt.w.s_2"] = "46000024FG", 432 | ["cvt.l.s_2"] = "46000025FG", 433 | ["cvt.ps.s_3"] = "46000026FGH", 434 | ["c.f.s_2"] = "46000030GH", 435 | ["c.f.s_3"] = "46000030VGH", 436 | ["c.un.s_2"] = "46000031GH", 437 | ["c.un.s_3"] = "46000031VGH", 438 | ["c.eq.s_2"] = "46000032GH", 439 | ["c.eq.s_3"] = "46000032VGH", 440 | ["c.ueq.s_2"] = "46000033GH", 441 | ["c.ueq.s_3"] = "46000033VGH", 442 | ["c.olt.s_2"] = "46000034GH", 443 | ["c.olt.s_3"] = "46000034VGH", 444 | ["c.ult.s_2"] = "46000035GH", 445 | ["c.ult.s_3"] = "46000035VGH", 446 | ["c.ole.s_2"] = "46000036GH", 447 | ["c.ole.s_3"] = "46000036VGH", 448 | ["c.ule.s_2"] = "46000037GH", 449 | ["c.ule.s_3"] = "46000037VGH", 450 | ["c.sf.s_2"] = "46000038GH", 451 | ["c.sf.s_3"] = "46000038VGH", 452 | ["c.ngle.s_2"] = "46000039GH", 453 | ["c.ngle.s_3"] = "46000039VGH", 454 | ["c.seq.s_2"] = "4600003aGH", 455 | ["c.seq.s_3"] = "4600003aVGH", 456 | ["c.ngl.s_2"] = "4600003bGH", 457 | ["c.ngl.s_3"] = "4600003bVGH", 458 | ["c.lt.s_2"] = "4600003cGH", 459 | ["c.lt.s_3"] = "4600003cVGH", 460 | ["c.nge.s_2"] = "4600003dGH", 461 | ["c.nge.s_3"] = "4600003dVGH", 462 | ["c.le.s_2"] = "4600003eGH", 463 | ["c.le.s_3"] = "4600003eVGH", 464 | ["c.ngt.s_2"] = "4600003fGH", 465 | ["c.ngt.s_3"] = "4600003fVGH", 466 | 467 | ["add.d_3"] = "46200000FGH", 468 | ["sub.d_3"] = "46200001FGH", 469 | ["mul.d_3"] = "46200002FGH", 470 | ["div.d_3"] = "46200003FGH", 471 | ["sqrt.d_2"] = "46200004FG", 472 | ["abs.d_2"] = "46200005FG", 473 | ["mov.d_2"] = "46200006FG", 474 | ["neg.d_2"] = "46200007FG", 475 | ["round.l.d_2"] = "46200008FG", 476 | ["trunc.l.d_2"] = "46200009FG", 477 | ["ceil.l.d_2"] = "4620000aFG", 478 | ["floor.l.d_2"] = "4620000bFG", 479 | ["round.w.d_2"] = "4620000cFG", 480 | ["trunc.w.d_2"] = "4620000dFG", 481 | ["ceil.w.d_2"] = "4620000eFG", 482 | ["floor.w.d_2"] = "4620000fFG", 483 | ["movf.d_2"] = "46200011FG", 484 | ["movf.d_3"] = "46200011FGC", 485 | ["movt.d_2"] = "46210011FG", 486 | ["movt.d_3"] = "46210011FGC", 487 | ["movz.d_3"] = "46200012FGT", 488 | ["movn.d_3"] = "46200013FGT", 489 | ["recip.d_2"] = "46200015FG", 490 | ["rsqrt.d_2"] = "46200016FG", 491 | ["cvt.s.d_2"] = "46200020FG", 492 | ["cvt.w.d_2"] = "46200024FG", 493 | ["cvt.l.d_2"] = "46200025FG", 494 | ["c.f.d_2"] = "46200030GH", 495 | ["c.f.d_3"] = "46200030VGH", 496 | ["c.un.d_2"] = "46200031GH", 497 | ["c.un.d_3"] = "46200031VGH", 498 | ["c.eq.d_2"] = "46200032GH", 499 | ["c.eq.d_3"] = "46200032VGH", 500 | ["c.ueq.d_2"] = "46200033GH", 501 | ["c.ueq.d_3"] = "46200033VGH", 502 | ["c.olt.d_2"] = "46200034GH", 503 | ["c.olt.d_3"] = "46200034VGH", 504 | ["c.ult.d_2"] = "46200035GH", 505 | ["c.ult.d_3"] = "46200035VGH", 506 | ["c.ole.d_2"] = "46200036GH", 507 | ["c.ole.d_3"] = "46200036VGH", 508 | ["c.ule.d_2"] = "46200037GH", 509 | ["c.ule.d_3"] = "46200037VGH", 510 | ["c.sf.d_2"] = "46200038GH", 511 | ["c.sf.d_3"] = "46200038VGH", 512 | ["c.ngle.d_2"] = "46200039GH", 513 | ["c.ngle.d_3"] = "46200039VGH", 514 | ["c.seq.d_2"] = "4620003aGH", 515 | ["c.seq.d_3"] = "4620003aVGH", 516 | ["c.ngl.d_2"] = "4620003bGH", 517 | ["c.ngl.d_3"] = "4620003bVGH", 518 | ["c.lt.d_2"] = "4620003cGH", 519 | ["c.lt.d_3"] = "4620003cVGH", 520 | ["c.nge.d_2"] = "4620003dGH", 521 | ["c.nge.d_3"] = "4620003dVGH", 522 | ["c.le.d_2"] = "4620003eGH", 523 | ["c.le.d_3"] = "4620003eVGH", 524 | ["c.ngt.d_2"] = "4620003fGH", 525 | ["c.ngt.d_3"] = "4620003fVGH", 526 | 527 | ["add.ps_3"] = "46c00000FGH", 528 | ["sub.ps_3"] = "46c00001FGH", 529 | ["mul.ps_3"] = "46c00002FGH", 530 | ["abs.ps_2"] = "46c00005FG", 531 | ["mov.ps_2"] = "46c00006FG", 532 | ["neg.ps_2"] = "46c00007FG", 533 | ["movf.ps_2"] = "46c00011FG", 534 | ["movf.ps_3"] = "46c00011FGC", 535 | ["movt.ps_2"] = "46c10011FG", 536 | ["movt.ps_3"] = "46c10011FGC", 537 | ["movz.ps_3"] = "46c00012FGT", 538 | ["movn.ps_3"] = "46c00013FGT", 539 | ["cvt.s.pu_2"] = "46c00020FG", 540 | ["cvt.s.pl_2"] = "46c00028FG", 541 | ["pll.ps_3"] = "46c0002cFGH", 542 | ["plu.ps_3"] = "46c0002dFGH", 543 | ["pul.ps_3"] = "46c0002eFGH", 544 | ["puu.ps_3"] = "46c0002fFGH", 545 | ["c.f.ps_2"] = "46c00030GH", 546 | ["c.f.ps_3"] = "46c00030VGH", 547 | ["c.un.ps_2"] = "46c00031GH", 548 | ["c.un.ps_3"] = "46c00031VGH", 549 | ["c.eq.ps_2"] = "46c00032GH", 550 | ["c.eq.ps_3"] = "46c00032VGH", 551 | ["c.ueq.ps_2"] = "46c00033GH", 552 | ["c.ueq.ps_3"] = "46c00033VGH", 553 | ["c.olt.ps_2"] = "46c00034GH", 554 | ["c.olt.ps_3"] = "46c00034VGH", 555 | ["c.ult.ps_2"] = "46c00035GH", 556 | ["c.ult.ps_3"] = "46c00035VGH", 557 | ["c.ole.ps_2"] = "46c00036GH", 558 | ["c.ole.ps_3"] = "46c00036VGH", 559 | ["c.ule.ps_2"] = "46c00037GH", 560 | ["c.ule.ps_3"] = "46c00037VGH", 561 | ["c.sf.ps_2"] = "46c00038GH", 562 | ["c.sf.ps_3"] = "46c00038VGH", 563 | ["c.ngle.ps_2"] = "46c00039GH", 564 | ["c.ngle.ps_3"] = "46c00039VGH", 565 | ["c.seq.ps_2"] = "46c0003aGH", 566 | ["c.seq.ps_3"] = "46c0003aVGH", 567 | ["c.ngl.ps_2"] = "46c0003bGH", 568 | ["c.ngl.ps_3"] = "46c0003bVGH", 569 | ["c.lt.ps_2"] = "46c0003cGH", 570 | ["c.lt.ps_3"] = "46c0003cVGH", 571 | ["c.nge.ps_2"] = "46c0003dGH", 572 | ["c.nge.ps_3"] = "46c0003dVGH", 573 | ["c.le.ps_2"] = "46c0003eGH", 574 | ["c.le.ps_3"] = "46c0003eVGH", 575 | ["c.ngt.ps_2"] = "46c0003fGH", 576 | ["c.ngt.ps_3"] = "46c0003fVGH", 577 | 578 | ["cvt.s.w_2"] = "46800020FG", 579 | ["cvt.d.w_2"] = "46800021FG", 580 | 581 | ["cvt.s.l_2"] = "46a00020FG", 582 | ["cvt.d.l_2"] = "46a00021FG", 583 | 584 | -- Opcode COP1X. 585 | lwxc1_2 = "4c000000FX", 586 | ldxc1_2 = "4c000001FX", 587 | luxc1_2 = "4c000005FX", 588 | swxc1_2 = "4c000008FX", 589 | sdxc1_2 = "4c000009FX", 590 | suxc1_2 = "4c00000dFX", 591 | prefx_2 = "4c00000fMX", 592 | ["alnv.ps_4"] = "4c00001eFGHS", 593 | ["madd.s_4"] = "4c000020FRGH", 594 | ["madd.d_4"] = "4c000021FRGH", 595 | ["madd.ps_4"] = "4c000026FRGH", 596 | ["msub.s_4"] = "4c000028FRGH", 597 | ["msub.d_4"] = "4c000029FRGH", 598 | ["msub.ps_4"] = "4c00002eFRGH", 599 | ["nmadd.s_4"] = "4c000030FRGH", 600 | ["nmadd.d_4"] = "4c000031FRGH", 601 | ["nmadd.ps_4"] = "4c000036FRGH", 602 | ["nmsub.s_4"] = "4c000038FRGH", 603 | ["nmsub.d_4"] = "4c000039FRGH", 604 | ["nmsub.ps_4"] = "4c00003eFRGH", 605 | } 606 | 607 | ------------------------------------------------------------------------------ 608 | 609 | local function parse_gpr(expr) 610 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") 611 | local tp = map_type[tname or expr] 612 | if tp then 613 | local reg = ovreg or tp.reg 614 | if not reg then 615 | werror("type `"..(tname or expr).."' needs a register override") 616 | end 617 | expr = reg 618 | end 619 | local r = match(expr, "^r([1-3]?[0-9])$") 620 | if r then 621 | r = tonumber(r) 622 | if r <= 31 then return r, tp end 623 | end 624 | werror("bad register name `"..expr.."'") 625 | end 626 | 627 | local function parse_fpr(expr) 628 | local r = match(expr, "^f([1-3]?[0-9])$") 629 | if r then 630 | r = tonumber(r) 631 | if r <= 31 then return r end 632 | end 633 | werror("bad register name `"..expr.."'") 634 | end 635 | 636 | local function parse_imm(imm, bits, shift, scale, signed) 637 | local n = tonumber(imm) 638 | if n then 639 | local m = sar(n, scale) 640 | if shl(m, scale) == n then 641 | if signed then 642 | local s = sar(m, bits-1) 643 | if s == 0 then return shl(m, shift) 644 | elseif s == -1 then return shl(m + shl(1, bits), shift) end 645 | else 646 | if sar(m, bits) == 0 then return shl(m, shift) end 647 | end 648 | end 649 | werror("out of range immediate `"..imm.."'") 650 | elseif match(imm, "^[rf]([1-3]?[0-9])$") or 651 | match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then 652 | werror("expected immediate operand, got register") 653 | else 654 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) 655 | return 0 656 | end 657 | end 658 | 659 | local function parse_disp(disp) 660 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") 661 | if imm then 662 | local r = shl(parse_gpr(reg), 21) 663 | local extname = match(imm, "^extern%s+(%S+)$") 664 | if extname then 665 | waction("REL_EXT", map_extern[extname], nil, 1) 666 | return r 667 | else 668 | return r + parse_imm(imm, 16, 0, 0, true) 669 | end 670 | end 671 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") 672 | if reg and tailr ~= "" then 673 | local r, tp = parse_gpr(reg) 674 | if tp then 675 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) 676 | return shl(r, 21) 677 | end 678 | end 679 | werror("bad displacement `"..disp.."'") 680 | end 681 | 682 | local function parse_index(idx) 683 | local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") 684 | if rt then 685 | rt = parse_gpr(rt) 686 | rs = parse_gpr(rs) 687 | return shl(rt, 16) + shl(rs, 21) 688 | end 689 | werror("bad index `"..idx.."'") 690 | end 691 | 692 | local function parse_label(label, def) 693 | local prefix = sub(label, 1, 2) 694 | -- =>label (pc label reference) 695 | if prefix == "=>" then 696 | return "PC", 0, sub(label, 3) 697 | end 698 | -- ->name (global label reference) 699 | if prefix == "->" then 700 | return "LG", map_global[sub(label, 3)] 701 | end 702 | if def then 703 | -- [1-9] (local label definition) 704 | if match(label, "^[1-9]$") then 705 | return "LG", 10+tonumber(label) 706 | end 707 | else 708 | -- [<>][1-9] (local label reference) 709 | local dir, lnum = match(label, "^([<>])([1-9])$") 710 | if dir then -- Fwd: 1-9, Bkwd: 11-19. 711 | return "LG", lnum + (dir == ">" and 0 or 10) 712 | end 713 | -- extern label (extern label reference) 714 | local extname = match(label, "^extern%s+(%S+)$") 715 | if extname then 716 | return "EXT", map_extern[extname] 717 | end 718 | end 719 | werror("bad label `"..label.."'") 720 | end 721 | 722 | ------------------------------------------------------------------------------ 723 | 724 | -- Handle opcodes defined with template strings. 725 | map_op[".template__"] = function(params, template, nparams) 726 | if not params then return sub(template, 9) end 727 | local op = tonumber(sub(template, 1, 8), 16) 728 | local n = 1 729 | 730 | -- Limit number of section buffer positions used by a single dasm_put(). 731 | -- A single opcode needs a maximum of 2 positions (ins/ext). 732 | if secpos+2 > maxsecpos then wflush() end 733 | local pos = wpos() 734 | 735 | -- Process each character. 736 | for p in gmatch(sub(template, 9), ".") do 737 | if p == "D" then 738 | op = op + shl(parse_gpr(params[n]), 11); n = n + 1 739 | elseif p == "T" then 740 | op = op + shl(parse_gpr(params[n]), 16); n = n + 1 741 | elseif p == "S" then 742 | op = op + shl(parse_gpr(params[n]), 21); n = n + 1 743 | elseif p == "F" then 744 | op = op + shl(parse_fpr(params[n]), 6); n = n + 1 745 | elseif p == "G" then 746 | op = op + shl(parse_fpr(params[n]), 11); n = n + 1 747 | elseif p == "H" then 748 | op = op + shl(parse_fpr(params[n]), 16); n = n + 1 749 | elseif p == "R" then 750 | op = op + shl(parse_fpr(params[n]), 21); n = n + 1 751 | elseif p == "I" then 752 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 753 | elseif p == "U" then 754 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 755 | elseif p == "O" then 756 | op = op + parse_disp(params[n]); n = n + 1 757 | elseif p == "X" then 758 | op = op + parse_index(params[n]); n = n + 1 759 | elseif p == "B" or p == "J" then 760 | local mode, n, s = parse_label(params[n], false) 761 | if p == "B" then n = n + 2048 end 762 | waction("REL_"..mode, n, s, 1) 763 | n = n + 1 764 | elseif p == "A" then 765 | op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 766 | elseif p == "M" then 767 | op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 768 | elseif p == "N" then 769 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 770 | elseif p == "C" then 771 | op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 772 | elseif p == "V" then 773 | op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 774 | elseif p == "W" then 775 | op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 776 | elseif p == "Y" then 777 | op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 778 | elseif p == "Z" then 779 | op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 780 | elseif p == "=" then 781 | op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo. 782 | else 783 | assert(false) 784 | end 785 | end 786 | wputpos(pos, op) 787 | end 788 | 789 | ------------------------------------------------------------------------------ 790 | 791 | -- Pseudo-opcode to mark the position where the action list is to be emitted. 792 | map_op[".actionlist_1"] = function(params) 793 | if not params then return "cvar" end 794 | local name = params[1] -- No syntax check. You get to keep the pieces. 795 | wline(function(out) writeactions(out, name) end) 796 | end 797 | 798 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. 799 | map_op[".globals_1"] = function(params) 800 | if not params then return "prefix" end 801 | local prefix = params[1] -- No syntax check. You get to keep the pieces. 802 | wline(function(out) writeglobals(out, prefix) end) 803 | end 804 | 805 | -- Pseudo-opcode to mark the position where the global names are to be emitted. 806 | map_op[".globalnames_1"] = function(params) 807 | if not params then return "cvar" end 808 | local name = params[1] -- No syntax check. You get to keep the pieces. 809 | wline(function(out) writeglobalnames(out, name) end) 810 | end 811 | 812 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. 813 | map_op[".externnames_1"] = function(params) 814 | if not params then return "cvar" end 815 | local name = params[1] -- No syntax check. You get to keep the pieces. 816 | wline(function(out) writeexternnames(out, name) end) 817 | end 818 | 819 | ------------------------------------------------------------------------------ 820 | 821 | -- Label pseudo-opcode (converted from trailing colon form). 822 | map_op[".label_1"] = function(params) 823 | if not params then return "[1-9] | ->global | =>pcexpr" end 824 | if secpos+1 > maxsecpos then wflush() end 825 | local mode, n, s = parse_label(params[1], true) 826 | if mode == "EXT" then werror("bad label definition") end 827 | waction("LABEL_"..mode, n, s, 1) 828 | end 829 | 830 | ------------------------------------------------------------------------------ 831 | 832 | -- Pseudo-opcodes for data storage. 833 | map_op[".long_*"] = function(params) 834 | if not params then return "imm..." end 835 | for _,p in ipairs(params) do 836 | local n = tonumber(p) 837 | if not n then werror("bad immediate `"..p.."'") end 838 | if n < 0 then n = n + 2^32 end 839 | wputw(n) 840 | if secpos+2 > maxsecpos then wflush() end 841 | end 842 | end 843 | 844 | -- Alignment pseudo-opcode. 845 | map_op[".align_1"] = function(params) 846 | if not params then return "numpow2" end 847 | if secpos+1 > maxsecpos then wflush() end 848 | local align = tonumber(params[1]) 849 | if align then 850 | local x = align 851 | -- Must be a power of 2 in the range (2 ... 256). 852 | for i=1,8 do 853 | x = x / 2 854 | if x == 1 then 855 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. 856 | return 857 | end 858 | end 859 | end 860 | werror("bad alignment") 861 | end 862 | 863 | ------------------------------------------------------------------------------ 864 | 865 | -- Pseudo-opcode for (primitive) type definitions (map to C types). 866 | map_op[".type_3"] = function(params, nparams) 867 | if not params then 868 | return nparams == 2 and "name, ctype" or "name, ctype, reg" 869 | end 870 | local name, ctype, reg = params[1], params[2], params[3] 871 | if not match(name, "^[%a_][%w_]*$") then 872 | werror("bad type name `"..name.."'") 873 | end 874 | local tp = map_type[name] 875 | if tp then 876 | werror("duplicate type `"..name.."'") 877 | end 878 | -- Add #type to defines. A bit unclean to put it in map_archdef. 879 | map_archdef["#"..name] = "sizeof("..ctype..")" 880 | -- Add new type and emit shortcut define. 881 | local num = ctypenum + 1 882 | map_type[name] = { 883 | ctype = ctype, 884 | ctypefmt = format("Dt%X(%%s)", num), 885 | reg = reg, 886 | } 887 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) 888 | ctypenum = num 889 | end 890 | map_op[".type_2"] = map_op[".type_3"] 891 | 892 | -- Dump type definitions. 893 | local function dumptypes(out, lvl) 894 | local t = {} 895 | for name in pairs(map_type) do t[#t+1] = name end 896 | sort(t) 897 | out:write("Type definitions:\n") 898 | for _,name in ipairs(t) do 899 | local tp = map_type[name] 900 | local reg = tp.reg or "" 901 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) 902 | end 903 | out:write("\n") 904 | end 905 | 906 | ------------------------------------------------------------------------------ 907 | 908 | -- Set the current section. 909 | function _M.section(num) 910 | waction("SECTION", num) 911 | wflush(true) -- SECTION is a terminal action. 912 | end 913 | 914 | ------------------------------------------------------------------------------ 915 | 916 | -- Dump architecture description. 917 | function _M.dumparch(out) 918 | out:write(format("DynASM %s version %s, released %s\n\n", 919 | _info.arch, _info.version, _info.release)) 920 | dumpactions(out) 921 | end 922 | 923 | -- Dump all user defined elements. 924 | function _M.dumpdef(out, lvl) 925 | dumptypes(out, lvl) 926 | dumpglobals(out, lvl) 927 | dumpexterns(out, lvl) 928 | end 929 | 930 | ------------------------------------------------------------------------------ 931 | 932 | -- Pass callbacks from/to the DynASM core. 933 | function _M.passcb(wl, we, wf, ww) 934 | wline, werror, wfatal, wwarn = wl, we, wf, ww 935 | return wflush 936 | end 937 | 938 | -- Setup the arch-specific module. 939 | function _M.setup(arch, opt) 940 | g_arch, g_opt = arch, opt 941 | end 942 | 943 | -- Merge the core maps and the arch-specific maps. 944 | function _M.mergemaps(map_coreop, map_def) 945 | setmetatable(map_op, { __index = map_coreop }) 946 | setmetatable(map_def, { __index = map_archdef }) 947 | return map_op, map_def 948 | end 949 | 950 | return _M 951 | 952 | ------------------------------------------------------------------------------ 953 | 954 | -------------------------------------------------------------------------------- /dynasm/dasm_ppc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM PPC/PPC64 encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "ppc" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. */ 19 | enum { 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, 21 | /* The following actions need a buffer position. */ 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, 23 | /* The following actions also have an argument. */ 24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, 25 | DASM__MAX 26 | }; 27 | 28 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 29 | #define DASM_MAXSECPOS 25 30 | 31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 32 | #define DASM_S_OK 0x00000000 33 | #define DASM_S_NOMEM 0x01000000 34 | #define DASM_S_PHASE 0x02000000 35 | #define DASM_S_MATCH_SEC 0x03000000 36 | #define DASM_S_RANGE_I 0x11000000 37 | #define DASM_S_RANGE_SEC 0x12000000 38 | #define DASM_S_RANGE_LG 0x13000000 39 | #define DASM_S_RANGE_PC 0x14000000 40 | #define DASM_S_RANGE_REL 0x15000000 41 | #define DASM_S_UNDEF_LG 0x21000000 42 | #define DASM_S_UNDEF_PC 0x22000000 43 | 44 | /* Macros to convert positions (8 bit section + 24 bit index). */ 45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 47 | #define DASM_SEC2POS(sec) ((sec)<<24) 48 | #define DASM_POS2SEC(pos) ((pos)>>24) 49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 50 | 51 | /* Action list type. */ 52 | typedef const unsigned int *dasm_ActList; 53 | 54 | /* Per-section structure. */ 55 | typedef struct dasm_Section { 56 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 57 | int *buf; /* True buffer pointer. */ 58 | size_t bsize; /* Buffer size in bytes. */ 59 | int pos; /* Biased buffer position. */ 60 | int epos; /* End of biased buffer position - max single put. */ 61 | int ofs; /* Byte offset into section. */ 62 | } dasm_Section; 63 | 64 | /* Core structure holding the DynASM encoding state. */ 65 | struct dasm_State { 66 | size_t psize; /* Allocated size of this structure. */ 67 | dasm_ActList actionlist; /* Current actionlist pointer. */ 68 | int *lglabels; /* Local/global chain/pos ptrs. */ 69 | size_t lgsize; 70 | int *pclabels; /* PC label chains/pos ptrs. */ 71 | size_t pcsize; 72 | void **globals; /* Array of globals (bias -10). */ 73 | dasm_Section *section; /* Pointer to active section. */ 74 | size_t codesize; /* Total size of all code sections. */ 75 | int maxsection; /* 0 <= sectionidx < maxsection. */ 76 | int status; /* Status code. */ 77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 78 | }; 79 | 80 | /* The size of the core structure depends on the max. number of sections. */ 81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 82 | 83 | 84 | /* Initialize DynASM state. */ 85 | void dasm_init(Dst_DECL, int maxsection) 86 | { 87 | dasm_State *D; 88 | size_t psz = 0; 89 | int i; 90 | Dst_REF = NULL; 91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 92 | D = Dst_REF; 93 | D->psize = psz; 94 | D->lglabels = NULL; 95 | D->lgsize = 0; 96 | D->pclabels = NULL; 97 | D->pcsize = 0; 98 | D->globals = NULL; 99 | D->maxsection = maxsection; 100 | for (i = 0; i < maxsection; i++) { 101 | D->sections[i].buf = NULL; /* Need this for pass3. */ 102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 103 | D->sections[i].bsize = 0; 104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 105 | } 106 | } 107 | 108 | /* Free DynASM state. */ 109 | void dasm_free(Dst_DECL) 110 | { 111 | dasm_State *D = Dst_REF; 112 | int i; 113 | for (i = 0; i < D->maxsection; i++) 114 | if (D->sections[i].buf) 115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 118 | DASM_M_FREE(Dst, D, D->psize); 119 | } 120 | 121 | /* Setup global label array. Must be called before dasm_setup(). */ 122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 123 | { 124 | dasm_State *D = Dst_REF; 125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 127 | } 128 | 129 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 130 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 131 | { 132 | dasm_State *D = Dst_REF; 133 | size_t osz = D->pcsize; 134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 136 | } 137 | 138 | /* Setup encoder. */ 139 | void dasm_setup(Dst_DECL, const void *actionlist) 140 | { 141 | dasm_State *D = Dst_REF; 142 | int i; 143 | D->actionlist = (dasm_ActList)actionlist; 144 | D->status = DASM_S_OK; 145 | D->section = &D->sections[0]; 146 | memset((void *)D->lglabels, 0, D->lgsize); 147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 148 | for (i = 0; i < D->maxsection; i++) { 149 | D->sections[i].pos = DASM_SEC2POS(i); 150 | D->sections[i].ofs = 0; 151 | } 152 | } 153 | 154 | 155 | #ifdef DASM_CHECKS 156 | #define CK(x, st) \ 157 | do { if (!(x)) { \ 158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) 159 | #define CKPL(kind, st) \ 160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) 162 | #else 163 | #define CK(x, st) ((void)0) 164 | #define CKPL(kind, st) ((void)0) 165 | #endif 166 | 167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 168 | void dasm_put(Dst_DECL, int start, ...) 169 | { 170 | va_list ap; 171 | dasm_State *D = Dst_REF; 172 | dasm_ActList p = D->actionlist + start; 173 | dasm_Section *sec = D->section; 174 | int pos = sec->pos, ofs = sec->ofs; 175 | int *b; 176 | 177 | if (pos >= sec->epos) { 178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 182 | } 183 | 184 | b = sec->rbuf; 185 | b[pos++] = start; 186 | 187 | va_start(ap, start); 188 | while (1) { 189 | unsigned int ins = *p++; 190 | unsigned int action = (ins >> 16); 191 | if (action >= DASM__MAX) { 192 | ofs += 4; 193 | } else { 194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; 195 | switch (action) { 196 | case DASM_STOP: goto stop; 197 | case DASM_SECTION: 198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); 199 | D->section = &D->sections[n]; goto stop; 200 | case DASM_ESC: p++; ofs += 4; break; 201 | case DASM_REL_EXT: break; 202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; 203 | case DASM_REL_LG: 204 | n = (ins & 2047) - 10; pl = D->lglabels + n; 205 | /* Bkwd rel or global. */ 206 | if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 207 | pl += 10; n = *pl; 208 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 209 | goto linkrel; 210 | case DASM_REL_PC: 211 | pl = D->pclabels + n; CKPL(pc, PC); 212 | putrel: 213 | n = *pl; 214 | if (n < 0) { /* Label exists. Get label pos and store it. */ 215 | b[pos] = -n; 216 | } else { 217 | linkrel: 218 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 219 | *pl = pos; 220 | } 221 | pos++; 222 | break; 223 | case DASM_LABEL_LG: 224 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; 225 | case DASM_LABEL_PC: 226 | pl = D->pclabels + n; CKPL(pc, PC); 227 | putlabel: 228 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 229 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; 230 | } 231 | *pl = -pos; /* Label exists now. */ 232 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 233 | break; 234 | case DASM_IMM: 235 | #ifdef DASM_CHECKS 236 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); 237 | #endif 238 | n >>= ((ins>>10)&31); 239 | #ifdef DASM_CHECKS 240 | if (ins & 0x8000) 241 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); 242 | else 243 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); 244 | #endif 245 | b[pos++] = n; 246 | break; 247 | case DASM_IMMSH: 248 | CK((n >> 6) == 0, RANGE_I); 249 | b[pos++] = n; 250 | break; 251 | } 252 | } 253 | } 254 | stop: 255 | va_end(ap); 256 | sec->pos = pos; 257 | sec->ofs = ofs; 258 | } 259 | #undef CK 260 | 261 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ 262 | int dasm_link(Dst_DECL, size_t *szp) 263 | { 264 | dasm_State *D = Dst_REF; 265 | int secnum; 266 | int ofs = 0; 267 | 268 | #ifdef DASM_CHECKS 269 | *szp = 0; 270 | if (D->status != DASM_S_OK) return D->status; 271 | { 272 | int pc; 273 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 274 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 275 | } 276 | #endif 277 | 278 | { /* Handle globals not defined in this translation unit. */ 279 | int idx; 280 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { 281 | int n = D->lglabels[idx]; 282 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 283 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 284 | } 285 | } 286 | 287 | /* Combine all code sections. No support for data sections (yet). */ 288 | for (secnum = 0; secnum < D->maxsection; secnum++) { 289 | dasm_Section *sec = D->sections + secnum; 290 | int *b = sec->rbuf; 291 | int pos = DASM_SEC2POS(secnum); 292 | int lastpos = sec->pos; 293 | 294 | while (pos != lastpos) { 295 | dasm_ActList p = D->actionlist + b[pos++]; 296 | while (1) { 297 | unsigned int ins = *p++; 298 | unsigned int action = (ins >> 16); 299 | switch (action) { 300 | case DASM_STOP: case DASM_SECTION: goto stop; 301 | case DASM_ESC: p++; break; 302 | case DASM_REL_EXT: break; 303 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; 304 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; 305 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; 306 | case DASM_IMM: case DASM_IMMSH: pos++; break; 307 | } 308 | } 309 | stop: (void)0; 310 | } 311 | ofs += sec->ofs; /* Next section starts right after current section. */ 312 | } 313 | 314 | D->codesize = ofs; /* Total size of all code sections */ 315 | *szp = ofs; 316 | return DASM_S_OK; 317 | } 318 | 319 | #ifdef DASM_CHECKS 320 | #define CK(x, st) \ 321 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) 322 | #else 323 | #define CK(x, st) ((void)0) 324 | #endif 325 | 326 | /* Pass 3: Encode sections. */ 327 | int dasm_encode(Dst_DECL, void *buffer) 328 | { 329 | dasm_State *D = Dst_REF; 330 | char *base = (char *)buffer; 331 | unsigned int *cp = (unsigned int *)buffer; 332 | int secnum; 333 | 334 | /* Encode all code sections. No support for data sections (yet). */ 335 | for (secnum = 0; secnum < D->maxsection; secnum++) { 336 | dasm_Section *sec = D->sections + secnum; 337 | int *b = sec->buf; 338 | int *endb = sec->rbuf + sec->pos; 339 | 340 | while (b != endb) { 341 | dasm_ActList p = D->actionlist + *b++; 342 | while (1) { 343 | unsigned int ins = *p++; 344 | unsigned int action = (ins >> 16); 345 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; 346 | switch (action) { 347 | case DASM_STOP: case DASM_SECTION: goto stop; 348 | case DASM_ESC: *cp++ = *p++; break; 349 | case DASM_REL_EXT: 350 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; 351 | goto patchrel; 352 | case DASM_ALIGN: 353 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; 354 | break; 355 | case DASM_REL_LG: 356 | CK(n >= 0, UNDEF_LG); 357 | case DASM_REL_PC: 358 | CK(n >= 0, UNDEF_PC); 359 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); 360 | patchrel: 361 | CK((n & 3) == 0 && 362 | (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> 363 | ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); 364 | cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); 365 | break; 366 | case DASM_LABEL_LG: 367 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); 368 | break; 369 | case DASM_LABEL_PC: break; 370 | case DASM_IMM: 371 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); 372 | break; 373 | case DASM_IMMSH: 374 | cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); 375 | break; 376 | default: *cp++ = ins; break; 377 | } 378 | } 379 | stop: (void)0; 380 | } 381 | } 382 | 383 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ 384 | return DASM_S_PHASE; 385 | return DASM_S_OK; 386 | } 387 | #undef CK 388 | 389 | /* Get PC label offset. */ 390 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 391 | { 392 | dasm_State *D = Dst_REF; 393 | if (pc*sizeof(int) < D->pcsize) { 394 | int pos = D->pclabels[pc]; 395 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 396 | if (pos > 0) return -1; /* Undefined. */ 397 | } 398 | return -2; /* Unused or out of range. */ 399 | } 400 | 401 | #ifdef DASM_CHECKS 402 | /* Optional sanity checker to call between isolated encoding steps. */ 403 | int dasm_checkstep(Dst_DECL, int secmatch) 404 | { 405 | dasm_State *D = Dst_REF; 406 | if (D->status == DASM_S_OK) { 407 | int i; 408 | for (i = 1; i <= 9; i++) { 409 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } 410 | D->lglabels[i] = 0; 411 | } 412 | } 413 | if (D->status == DASM_S_OK && secmatch >= 0 && 414 | D->section != &D->sections[secmatch]) 415 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); 416 | return D->status; 417 | } 418 | #endif 419 | 420 | -------------------------------------------------------------------------------- /dynasm/dasm_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM encoding engine prototypes. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #ifndef _DASM_PROTO_H 8 | #define _DASM_PROTO_H 9 | 10 | #include 11 | #include 12 | 13 | #define DASM_IDENT "DynASM 1.3.0" 14 | #define DASM_VERSION 10300 /* 1.3.0 */ 15 | 16 | #ifndef Dst_DECL 17 | #define Dst_DECL dasm_State **Dst 18 | #endif 19 | 20 | #ifndef Dst_REF 21 | #define Dst_REF (*Dst) 22 | #endif 23 | 24 | #ifndef DASM_FDEF 25 | #define DASM_FDEF extern 26 | #endif 27 | 28 | #ifndef DASM_M_GROW 29 | #define DASM_M_GROW(ctx, t, p, sz, need) \ 30 | do { \ 31 | size_t _sz = (sz), _need = (need); \ 32 | if (_sz < _need) { \ 33 | if (_sz < 16) _sz = 16; \ 34 | while (_sz < _need) _sz += _sz; \ 35 | (p) = (t *)realloc((p), _sz); \ 36 | if ((p) == NULL) exit(1); \ 37 | (sz) = _sz; \ 38 | } \ 39 | } while(0) 40 | #endif 41 | 42 | #ifndef DASM_M_FREE 43 | #define DASM_M_FREE(ctx, p, sz) free(p) 44 | #endif 45 | 46 | /* Internal DynASM encoder state. */ 47 | typedef struct dasm_State dasm_State; 48 | 49 | 50 | /* Initialize and free DynASM state. */ 51 | DASM_FDEF void dasm_init(Dst_DECL, int maxsection); 52 | DASM_FDEF void dasm_free(Dst_DECL); 53 | 54 | /* Setup global array. Must be called before dasm_setup(). */ 55 | DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); 56 | 57 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 58 | DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); 59 | 60 | /* Setup encoder. */ 61 | DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); 62 | 63 | /* Feed encoder with actions. Calls are generated by pre-processor. */ 64 | DASM_FDEF void dasm_put(Dst_DECL, int start, ...); 65 | 66 | /* Link sections and return the resulting size. */ 67 | DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); 68 | 69 | /* Encode sections into buffer. */ 70 | DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); 71 | 72 | /* Get PC label offset. */ 73 | DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); 74 | 75 | #ifdef DASM_CHECKS 76 | /* Optional sanity checker to call between isolated encoding steps. */ 77 | DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); 78 | #else 79 | #define dasm_checkstep(a, b) 0 80 | #endif 81 | 82 | 83 | #endif /* _DASM_PROTO_H */ 84 | -------------------------------------------------------------------------------- /dynasm/dasm_x64.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM x64 module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- See dynasm.lua for full copyright notice. 6 | ------------------------------------------------------------------------------ 7 | -- This module just sets 64 bit mode for the combined x86/x64 module. 8 | -- All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | x64 = true -- Using a global is an ugly, but effective solution. 12 | return require("dasm_x86") 13 | -------------------------------------------------------------------------------- /dynasm/dasm_x86.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** DynASM x86 encoding engine. 3 | ** Copyright (C) 2005-2015 Mike Pall. All rights reserved. 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DASM_ARCH "x86" 13 | 14 | #ifndef DASM_EXTERN 15 | #define DASM_EXTERN(a,b,c,d) 0 16 | #endif 17 | 18 | /* Action definitions. DASM_STOP must be 255. */ 19 | enum { 20 | DASM_DISP = 233, 21 | DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, 22 | DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, 23 | DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, 24 | DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP 25 | }; 26 | 27 | /* Maximum number of section buffer positions for a single dasm_put() call. */ 28 | #define DASM_MAXSECPOS 25 29 | 30 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ 31 | #define DASM_S_OK 0x00000000 32 | #define DASM_S_NOMEM 0x01000000 33 | #define DASM_S_PHASE 0x02000000 34 | #define DASM_S_MATCH_SEC 0x03000000 35 | #define DASM_S_RANGE_I 0x11000000 36 | #define DASM_S_RANGE_SEC 0x12000000 37 | #define DASM_S_RANGE_LG 0x13000000 38 | #define DASM_S_RANGE_PC 0x14000000 39 | #define DASM_S_RANGE_VREG 0x15000000 40 | #define DASM_S_UNDEF_L 0x21000000 41 | #define DASM_S_UNDEF_PC 0x22000000 42 | 43 | /* Macros to convert positions (8 bit section + 24 bit index). */ 44 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) 45 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) 46 | #define DASM_SEC2POS(sec) ((sec)<<24) 47 | #define DASM_POS2SEC(pos) ((pos)>>24) 48 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) 49 | 50 | /* Action list type. */ 51 | typedef const unsigned char *dasm_ActList; 52 | 53 | /* Per-section structure. */ 54 | typedef struct dasm_Section { 55 | int *rbuf; /* Biased buffer pointer (negative section bias). */ 56 | int *buf; /* True buffer pointer. */ 57 | size_t bsize; /* Buffer size in bytes. */ 58 | int pos; /* Biased buffer position. */ 59 | int epos; /* End of biased buffer position - max single put. */ 60 | int ofs; /* Byte offset into section. */ 61 | } dasm_Section; 62 | 63 | /* Core structure holding the DynASM encoding state. */ 64 | struct dasm_State { 65 | size_t psize; /* Allocated size of this structure. */ 66 | dasm_ActList actionlist; /* Current actionlist pointer. */ 67 | int *lglabels; /* Local/global chain/pos ptrs. */ 68 | size_t lgsize; 69 | int *pclabels; /* PC label chains/pos ptrs. */ 70 | size_t pcsize; 71 | void **globals; /* Array of globals (bias -10). */ 72 | dasm_Section *section; /* Pointer to active section. */ 73 | size_t codesize; /* Total size of all code sections. */ 74 | int maxsection; /* 0 <= sectionidx < maxsection. */ 75 | int status; /* Status code. */ 76 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ 77 | }; 78 | 79 | /* The size of the core structure depends on the max. number of sections. */ 80 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) 81 | 82 | 83 | /* Initialize DynASM state. */ 84 | void dasm_init(Dst_DECL, int maxsection) 85 | { 86 | dasm_State *D; 87 | size_t psz = 0; 88 | int i; 89 | Dst_REF = NULL; 90 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); 91 | D = Dst_REF; 92 | D->psize = psz; 93 | D->lglabels = NULL; 94 | D->lgsize = 0; 95 | D->pclabels = NULL; 96 | D->pcsize = 0; 97 | D->globals = NULL; 98 | D->maxsection = maxsection; 99 | for (i = 0; i < maxsection; i++) { 100 | D->sections[i].buf = NULL; /* Need this for pass3. */ 101 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); 102 | D->sections[i].bsize = 0; 103 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ 104 | } 105 | } 106 | 107 | /* Free DynASM state. */ 108 | void dasm_free(Dst_DECL) 109 | { 110 | dasm_State *D = Dst_REF; 111 | int i; 112 | for (i = 0; i < D->maxsection; i++) 113 | if (D->sections[i].buf) 114 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); 115 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); 116 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); 117 | DASM_M_FREE(Dst, D, D->psize); 118 | } 119 | 120 | /* Setup global label array. Must be called before dasm_setup(). */ 121 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) 122 | { 123 | dasm_State *D = Dst_REF; 124 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ 125 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); 126 | } 127 | 128 | /* Grow PC label array. Can be called after dasm_setup(), too. */ 129 | void dasm_growpc(Dst_DECL, unsigned int maxpc) 130 | { 131 | dasm_State *D = Dst_REF; 132 | size_t osz = D->pcsize; 133 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); 134 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); 135 | } 136 | 137 | /* Setup encoder. */ 138 | void dasm_setup(Dst_DECL, const void *actionlist) 139 | { 140 | dasm_State *D = Dst_REF; 141 | int i; 142 | D->actionlist = (dasm_ActList)actionlist; 143 | D->status = DASM_S_OK; 144 | D->section = &D->sections[0]; 145 | memset((void *)D->lglabels, 0, D->lgsize); 146 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); 147 | for (i = 0; i < D->maxsection; i++) { 148 | D->sections[i].pos = DASM_SEC2POS(i); 149 | D->sections[i].ofs = 0; 150 | } 151 | } 152 | 153 | 154 | #ifdef DASM_CHECKS 155 | #define CK(x, st) \ 156 | do { if (!(x)) { \ 157 | D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) 158 | #define CKPL(kind, st) \ 159 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ 160 | D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) 161 | #else 162 | #define CK(x, st) ((void)0) 163 | #define CKPL(kind, st) ((void)0) 164 | #endif 165 | 166 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ 167 | void dasm_put(Dst_DECL, int start, ...) 168 | { 169 | va_list ap; 170 | dasm_State *D = Dst_REF; 171 | dasm_ActList p = D->actionlist + start; 172 | dasm_Section *sec = D->section; 173 | int pos = sec->pos, ofs = sec->ofs, mrm = 4; 174 | int *b; 175 | 176 | if (pos >= sec->epos) { 177 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, 178 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); 179 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); 180 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); 181 | } 182 | 183 | b = sec->rbuf; 184 | b[pos++] = start; 185 | 186 | va_start(ap, start); 187 | while (1) { 188 | int action = *p++; 189 | if (action < DASM_DISP) { 190 | ofs++; 191 | } else if (action <= DASM_REL_A) { 192 | int n = va_arg(ap, int); 193 | b[pos++] = n; 194 | switch (action) { 195 | case DASM_DISP: 196 | if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } 197 | case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; 198 | case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ 199 | case DASM_IMM_D: ofs += 4; break; 200 | case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; 201 | case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; 202 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; 203 | case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; 204 | case DASM_SPACE: p++; ofs += n; break; 205 | case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ 206 | case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); 207 | if (*p++ == 1 && *p == DASM_DISP) mrm = n; 208 | continue; 209 | } 210 | mrm = 4; 211 | } else { 212 | int *pl, n; 213 | switch (action) { 214 | case DASM_REL_LG: 215 | case DASM_IMM_LG: 216 | n = *p++; pl = D->lglabels + n; 217 | /* Bkwd rel or global. */ 218 | if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } 219 | pl -= 246; n = *pl; 220 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ 221 | goto linkrel; 222 | case DASM_REL_PC: 223 | case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 224 | putrel: 225 | n = *pl; 226 | if (n < 0) { /* Label exists. Get label pos and store it. */ 227 | b[pos] = -n; 228 | } else { 229 | linkrel: 230 | b[pos] = n; /* Else link to rel chain, anchored at label. */ 231 | *pl = pos; 232 | } 233 | pos++; 234 | ofs += 4; /* Maximum offset needed. */ 235 | if (action == DASM_REL_LG || action == DASM_REL_PC) 236 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 237 | break; 238 | case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; 239 | case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); 240 | putlabel: 241 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ 242 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } 243 | *pl = -pos; /* Label exists now. */ 244 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 245 | break; 246 | case DASM_ALIGN: 247 | ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ 248 | b[pos++] = ofs; /* Store pass1 offset estimate. */ 249 | break; 250 | case DASM_EXTERN: p += 2; ofs += 4; break; 251 | case DASM_ESC: p++; ofs++; break; 252 | case DASM_MARK: mrm = p[-2]; break; 253 | case DASM_SECTION: 254 | n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; 255 | case DASM_STOP: goto stop; 256 | } 257 | } 258 | } 259 | stop: 260 | va_end(ap); 261 | sec->pos = pos; 262 | sec->ofs = ofs; 263 | } 264 | #undef CK 265 | 266 | /* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ 267 | int dasm_link(Dst_DECL, size_t *szp) 268 | { 269 | dasm_State *D = Dst_REF; 270 | int secnum; 271 | int ofs = 0; 272 | 273 | #ifdef DASM_CHECKS 274 | *szp = 0; 275 | if (D->status != DASM_S_OK) return D->status; 276 | { 277 | int pc; 278 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) 279 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; 280 | } 281 | #endif 282 | 283 | { /* Handle globals not defined in this translation unit. */ 284 | int idx; 285 | for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { 286 | int n = D->lglabels[idx]; 287 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ 288 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } 289 | } 290 | } 291 | 292 | /* Combine all code sections. No support for data sections (yet). */ 293 | for (secnum = 0; secnum < D->maxsection; secnum++) { 294 | dasm_Section *sec = D->sections + secnum; 295 | int *b = sec->rbuf; 296 | int pos = DASM_SEC2POS(secnum); 297 | int lastpos = sec->pos; 298 | 299 | while (pos != lastpos) { 300 | dasm_ActList p = D->actionlist + b[pos++]; 301 | while (1) { 302 | int op, action = *p++; 303 | switch (action) { 304 | case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; 305 | case DASM_REL_PC: op = p[-2]; rel_pc: { 306 | int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); 307 | if (shrink) { /* Shrinkable branch opcode? */ 308 | int lofs, lpos = b[pos]; 309 | if (lpos < 0) goto noshrink; /* Ext global? */ 310 | lofs = *DASM_POS2PTR(D, lpos); 311 | if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ 312 | int i; 313 | for (i = secnum; i < DASM_POS2SEC(lpos); i++) 314 | lofs += D->sections[i].ofs; 315 | } else { 316 | lofs -= ofs; /* Bkwd label: unfix offset. */ 317 | } 318 | lofs -= b[pos+1]; /* Short branch ok? */ 319 | if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ 320 | else { noshrink: shrink = 0; } /* No, cannot shrink op. */ 321 | } 322 | b[pos+1] = shrink; 323 | pos += 2; 324 | break; 325 | } 326 | case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; 327 | case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: 328 | case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: 329 | case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; 330 | case DASM_LABEL_LG: p++; 331 | case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ 332 | case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ 333 | case DASM_EXTERN: p += 2; break; 334 | case DASM_ESC: p++; break; 335 | case DASM_MARK: break; 336 | case DASM_SECTION: case DASM_STOP: goto stop; 337 | } 338 | } 339 | stop: (void)0; 340 | } 341 | ofs += sec->ofs; /* Next section starts right after current section. */ 342 | } 343 | 344 | D->codesize = ofs; /* Total size of all code sections */ 345 | *szp = ofs; 346 | return DASM_S_OK; 347 | } 348 | 349 | #define dasmb(x) *cp++ = (unsigned char)(x) 350 | #ifndef DASM_ALIGNED_WRITES 351 | #define dasmw(x) \ 352 | do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) 353 | #define dasmd(x) \ 354 | do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) 355 | #else 356 | #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) 357 | #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) 358 | #endif 359 | 360 | /* Pass 3: Encode sections. */ 361 | int dasm_encode(Dst_DECL, void *buffer) 362 | { 363 | dasm_State *D = Dst_REF; 364 | unsigned char *base = (unsigned char *)buffer; 365 | unsigned char *cp = base; 366 | int secnum; 367 | 368 | /* Encode all code sections. No support for data sections (yet). */ 369 | for (secnum = 0; secnum < D->maxsection; secnum++) { 370 | dasm_Section *sec = D->sections + secnum; 371 | int *b = sec->buf; 372 | int *endb = sec->rbuf + sec->pos; 373 | 374 | while (b != endb) { 375 | dasm_ActList p = D->actionlist + *b++; 376 | unsigned char *mark = NULL; 377 | while (1) { 378 | int action = *p++; 379 | int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; 380 | switch (action) { 381 | case DASM_DISP: if (!mark) mark = cp; { 382 | unsigned char *mm = mark; 383 | if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; 384 | if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; 385 | if (mrm != 5) { mm[-1] -= 0x80; break; } } 386 | if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; 387 | } 388 | case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; 389 | case DASM_IMM_DB: if (((n+128)&-256) == 0) { 390 | db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; 391 | } else mark = NULL; 392 | case DASM_IMM_D: wd: dasmd(n); break; 393 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; 394 | case DASM_IMM_W: dasmw(n); break; 395 | case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } 396 | case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; 397 | b++; n = (int)(ptrdiff_t)D->globals[-n]; 398 | case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ 399 | case DASM_REL_PC: rel_pc: { 400 | int shrink = *b++; 401 | int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } 402 | n = *pb - ((int)(cp-base) + 4-shrink); 403 | if (shrink == 0) goto wd; 404 | if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; 405 | goto wb; 406 | } 407 | case DASM_IMM_LG: 408 | p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } 409 | case DASM_IMM_PC: { 410 | int *pb = DASM_POS2PTR(D, n); 411 | n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); 412 | goto wd; 413 | } 414 | case DASM_LABEL_LG: { 415 | int idx = *p++; 416 | if (idx >= 10) 417 | D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); 418 | break; 419 | } 420 | case DASM_LABEL_PC: case DASM_SETLABEL: break; 421 | case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } 422 | case DASM_ALIGN: 423 | n = *p++; 424 | while (((cp-base) & n)) *cp++ = 0x90; /* nop */ 425 | break; 426 | case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; 427 | case DASM_MARK: mark = cp; break; 428 | case DASM_ESC: action = *p++; 429 | default: *cp++ = action; break; 430 | case DASM_SECTION: case DASM_STOP: goto stop; 431 | } 432 | } 433 | stop: (void)0; 434 | } 435 | } 436 | 437 | if (base + D->codesize != cp) /* Check for phase errors. */ 438 | return DASM_S_PHASE; 439 | return DASM_S_OK; 440 | } 441 | 442 | /* Get PC label offset. */ 443 | int dasm_getpclabel(Dst_DECL, unsigned int pc) 444 | { 445 | dasm_State *D = Dst_REF; 446 | if (pc*sizeof(int) < D->pcsize) { 447 | int pos = D->pclabels[pc]; 448 | if (pos < 0) return *DASM_POS2PTR(D, -pos); 449 | if (pos > 0) return -1; /* Undefined. */ 450 | } 451 | return -2; /* Unused or out of range. */ 452 | } 453 | 454 | #ifdef DASM_CHECKS 455 | /* Optional sanity checker to call between isolated encoding steps. */ 456 | int dasm_checkstep(Dst_DECL, int secmatch) 457 | { 458 | dasm_State *D = Dst_REF; 459 | if (D->status == DASM_S_OK) { 460 | int i; 461 | for (i = 1; i <= 9; i++) { 462 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } 463 | D->lglabels[i] = 0; 464 | } 465 | } 466 | if (D->status == DASM_S_OK && secmatch >= 0 && 467 | D->section != &D->sections[secmatch]) 468 | D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); 469 | return D->status; 470 | } 471 | #endif 472 | 473 | -------------------------------------------------------------------------------- /dynasm/dynasm.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- DynASM. A dynamic assembler for code generation engines. 3 | -- Originally designed and implemented for LuaJIT. 4 | -- 5 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 6 | -- See below for full copyright notice. 7 | ------------------------------------------------------------------------------ 8 | 9 | -- Application information. 10 | local _info = { 11 | name = "DynASM", 12 | description = "A dynamic assembler for code generation engines", 13 | version = "1.3.0", 14 | vernum = 10300, 15 | release = "2011-05-05", 16 | author = "Mike Pall", 17 | url = "http://luajit.org/dynasm.html", 18 | license = "MIT", 19 | copyright = [[ 20 | Copyright (C) 2005-2015 Mike Pall. All rights reserved. 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining 23 | a copy of this software and associated documentation files (the 24 | "Software"), to deal in the Software without restriction, including 25 | without limitation the rights to use, copy, modify, merge, publish, 26 | distribute, sublicense, and/or sell copies of the Software, and to 27 | permit persons to whom the Software is furnished to do so, subject to 28 | the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be 31 | included in all copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 36 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 37 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 38 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 39 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 40 | 41 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 42 | ]], 43 | } 44 | 45 | -- Cache library functions. 46 | local type, pairs, ipairs = type, pairs, ipairs 47 | local pcall, error, assert = pcall, error, assert 48 | local _s = string 49 | local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub 50 | local format, rep, upper = _s.format, _s.rep, _s.upper 51 | local _t = table 52 | local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort 53 | local exit = os.exit 54 | local io = io 55 | local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr 56 | 57 | ------------------------------------------------------------------------------ 58 | 59 | -- Program options. 60 | local g_opt = {} 61 | 62 | -- Global state for current file. 63 | local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch 64 | local g_errcount = 0 65 | 66 | -- Write buffer for output file. 67 | local g_wbuffer, g_capbuffer 68 | 69 | ------------------------------------------------------------------------------ 70 | 71 | -- Write an output line (or callback function) to the buffer. 72 | local function wline(line, needindent) 73 | local buf = g_capbuffer or g_wbuffer 74 | buf[#buf+1] = needindent and g_indent..line or line 75 | g_synclineno = g_synclineno + 1 76 | end 77 | 78 | -- Write assembler line as a comment, if requestd. 79 | local function wcomment(aline) 80 | if g_opt.comment then 81 | wline(g_opt.comment..aline..g_opt.endcomment, true) 82 | end 83 | end 84 | 85 | -- Resync CPP line numbers. 86 | local function wsync() 87 | if g_synclineno ~= g_lineno and g_opt.cpp then 88 | wline("#line "..g_lineno..' "'..g_fname..'"') 89 | g_synclineno = g_lineno 90 | end 91 | end 92 | 93 | -- Dummy action flush function. Replaced with arch-specific function later. 94 | local function wflush(term) 95 | end 96 | 97 | -- Dump all buffered output lines. 98 | local function wdumplines(out, buf) 99 | for _,line in ipairs(buf) do 100 | if type(line) == "string" then 101 | assert(out:write(line, "\n")) 102 | else 103 | -- Special callback to dynamically insert lines after end of processing. 104 | line(out) 105 | end 106 | end 107 | end 108 | 109 | ------------------------------------------------------------------------------ 110 | 111 | -- Emit an error. Processing continues with next statement. 112 | local function werror(msg) 113 | error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) 114 | end 115 | 116 | -- Emit a fatal error. Processing stops. 117 | local function wfatal(msg) 118 | g_errcount = "fatal" 119 | werror(msg) 120 | end 121 | 122 | -- Print a warning. Processing continues. 123 | local function wwarn(msg) 124 | stderr:write(format("%s:%s: warning: %s:\n%s\n", 125 | g_fname, g_lineno, msg, g_curline)) 126 | end 127 | 128 | -- Print caught error message. But suppress excessive errors. 129 | local function wprinterr(...) 130 | if type(g_errcount) == "number" then 131 | -- Regular error. 132 | g_errcount = g_errcount + 1 133 | if g_errcount < 21 then -- Seems to be a reasonable limit. 134 | stderr:write(...) 135 | elseif g_errcount == 21 then 136 | stderr:write(g_fname, 137 | ":*: warning: too many errors (suppressed further messages).\n") 138 | end 139 | else 140 | -- Fatal error. 141 | stderr:write(...) 142 | return true -- Stop processing. 143 | end 144 | end 145 | 146 | ------------------------------------------------------------------------------ 147 | 148 | -- Map holding all option handlers. 149 | local opt_map = {} 150 | local opt_current 151 | 152 | -- Print error and exit with error status. 153 | local function opterror(...) 154 | stderr:write("dynasm.lua: ERROR: ", ...) 155 | stderr:write("\n") 156 | exit(1) 157 | end 158 | 159 | -- Get option parameter. 160 | local function optparam(args) 161 | local argn = args.argn 162 | local p = args[argn] 163 | if not p then 164 | opterror("missing parameter for option `", opt_current, "'.") 165 | end 166 | args.argn = argn + 1 167 | return p 168 | end 169 | 170 | ------------------------------------------------------------------------------ 171 | 172 | -- Core pseudo-opcodes. 173 | local map_coreop = {} 174 | -- Dummy opcode map. Replaced by arch-specific map. 175 | local map_op = {} 176 | 177 | -- Forward declarations. 178 | local dostmt 179 | local readfile 180 | 181 | ------------------------------------------------------------------------------ 182 | 183 | -- Map for defines (initially empty, chains to arch-specific map). 184 | local map_def = {} 185 | 186 | -- Pseudo-opcode to define a substitution. 187 | map_coreop[".define_2"] = function(params, nparams) 188 | if not params then return nparams == 1 and "name" or "name, subst" end 189 | local name, def = params[1], params[2] or "1" 190 | if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end 191 | map_def[name] = def 192 | end 193 | map_coreop[".define_1"] = map_coreop[".define_2"] 194 | 195 | -- Define a substitution on the command line. 196 | function opt_map.D(args) 197 | local namesubst = optparam(args) 198 | local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") 199 | if name then 200 | map_def[name] = subst 201 | elseif match(namesubst, "^[%a_][%w_]*$") then 202 | map_def[namesubst] = "1" 203 | else 204 | opterror("bad define") 205 | end 206 | end 207 | 208 | -- Undefine a substitution on the command line. 209 | function opt_map.U(args) 210 | local name = optparam(args) 211 | if match(name, "^[%a_][%w_]*$") then 212 | map_def[name] = nil 213 | else 214 | opterror("bad define") 215 | end 216 | end 217 | 218 | -- Helper for definesubst. 219 | local gotsubst 220 | 221 | local function definesubst_one(word) 222 | local subst = map_def[word] 223 | if subst then gotsubst = word; return subst else return word end 224 | end 225 | 226 | -- Iteratively substitute defines. 227 | local function definesubst(stmt) 228 | -- Limit number of iterations. 229 | for i=1,100 do 230 | gotsubst = false 231 | stmt = gsub(stmt, "#?[%w_]+", definesubst_one) 232 | if not gotsubst then break end 233 | end 234 | if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end 235 | return stmt 236 | end 237 | 238 | -- Dump all defines. 239 | local function dumpdefines(out, lvl) 240 | local t = {} 241 | for name in pairs(map_def) do 242 | t[#t+1] = name 243 | end 244 | sort(t) 245 | out:write("Defines:\n") 246 | for _,name in ipairs(t) do 247 | local subst = map_def[name] 248 | if g_arch then subst = g_arch.revdef(subst) end 249 | out:write(format(" %-20s %s\n", name, subst)) 250 | end 251 | out:write("\n") 252 | end 253 | 254 | ------------------------------------------------------------------------------ 255 | 256 | -- Support variables for conditional assembly. 257 | local condlevel = 0 258 | local condstack = {} 259 | 260 | -- Evaluate condition with a Lua expression. Substitutions already performed. 261 | local function cond_eval(cond) 262 | local func, err 263 | if setfenv then 264 | func, err = loadstring("return "..cond, "=expr") 265 | else 266 | -- No globals. All unknown identifiers evaluate to nil. 267 | func, err = load("return "..cond, "=expr", "t", {}) 268 | end 269 | if func then 270 | if setfenv then 271 | setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. 272 | end 273 | local ok, res = pcall(func) 274 | if ok then 275 | if res == 0 then return false end -- Oh well. 276 | return not not res 277 | end 278 | err = res 279 | end 280 | wfatal("bad condition: "..err) 281 | end 282 | 283 | -- Skip statements until next conditional pseudo-opcode at the same level. 284 | local function stmtskip() 285 | local dostmt_save = dostmt 286 | local lvl = 0 287 | dostmt = function(stmt) 288 | local op = match(stmt, "^%s*(%S+)") 289 | if op == ".if" then 290 | lvl = lvl + 1 291 | elseif lvl ~= 0 then 292 | if op == ".endif" then lvl = lvl - 1 end 293 | elseif op == ".elif" or op == ".else" or op == ".endif" then 294 | dostmt = dostmt_save 295 | dostmt(stmt) 296 | end 297 | end 298 | end 299 | 300 | -- Pseudo-opcodes for conditional assembly. 301 | map_coreop[".if_1"] = function(params) 302 | if not params then return "condition" end 303 | local lvl = condlevel + 1 304 | local res = cond_eval(params[1]) 305 | condlevel = lvl 306 | condstack[lvl] = res 307 | if not res then stmtskip() end 308 | end 309 | 310 | map_coreop[".elif_1"] = function(params) 311 | if not params then return "condition" end 312 | if condlevel == 0 then wfatal(".elif without .if") end 313 | local lvl = condlevel 314 | local res = condstack[lvl] 315 | if res then 316 | if res == "else" then wfatal(".elif after .else") end 317 | else 318 | res = cond_eval(params[1]) 319 | if res then 320 | condstack[lvl] = res 321 | return 322 | end 323 | end 324 | stmtskip() 325 | end 326 | 327 | map_coreop[".else_0"] = function(params) 328 | if condlevel == 0 then wfatal(".else without .if") end 329 | local lvl = condlevel 330 | local res = condstack[lvl] 331 | condstack[lvl] = "else" 332 | if res then 333 | if res == "else" then wfatal(".else after .else") end 334 | stmtskip() 335 | end 336 | end 337 | 338 | map_coreop[".endif_0"] = function(params) 339 | local lvl = condlevel 340 | if lvl == 0 then wfatal(".endif without .if") end 341 | condlevel = lvl - 1 342 | end 343 | 344 | -- Check for unfinished conditionals. 345 | local function checkconds() 346 | if g_errcount ~= "fatal" and condlevel ~= 0 then 347 | wprinterr(g_fname, ":*: error: unbalanced conditional\n") 348 | end 349 | end 350 | 351 | ------------------------------------------------------------------------------ 352 | 353 | -- Search for a file in the given path and open it for reading. 354 | local function pathopen(path, name) 355 | local dirsep = package and match(package.path, "\\") and "\\" or "/" 356 | for _,p in ipairs(path) do 357 | local fullname = p == "" and name or p..dirsep..name 358 | local fin = io.open(fullname, "r") 359 | if fin then 360 | g_fname = fullname 361 | return fin 362 | end 363 | end 364 | end 365 | 366 | -- Include a file. 367 | map_coreop[".include_1"] = function(params) 368 | if not params then return "filename" end 369 | local name = params[1] 370 | -- Save state. Ugly, I know. but upvalues are fast. 371 | local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent 372 | -- Read the included file. 373 | local fatal = readfile(pathopen(g_opt.include, name) or 374 | wfatal("include file `"..name.."' not found")) 375 | -- Restore state. 376 | g_synclineno = -1 377 | g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi 378 | if fatal then wfatal("in include file") end 379 | end 380 | 381 | -- Make .include and conditionals initially available, too. 382 | map_op[".include_1"] = map_coreop[".include_1"] 383 | map_op[".if_1"] = map_coreop[".if_1"] 384 | map_op[".elif_1"] = map_coreop[".elif_1"] 385 | map_op[".else_0"] = map_coreop[".else_0"] 386 | map_op[".endif_0"] = map_coreop[".endif_0"] 387 | 388 | ------------------------------------------------------------------------------ 389 | 390 | -- Support variables for macros. 391 | local mac_capture, mac_lineno, mac_name 392 | local mac_active = {} 393 | local mac_list = {} 394 | 395 | -- Pseudo-opcode to define a macro. 396 | map_coreop[".macro_*"] = function(mparams) 397 | if not mparams then return "name [, params...]" end 398 | -- Split off and validate macro name. 399 | local name = remove(mparams, 1) 400 | if not name then werror("missing macro name") end 401 | if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then 402 | wfatal("bad macro name `"..name.."'") 403 | end 404 | -- Validate macro parameter names. 405 | local mdup = {} 406 | for _,mp in ipairs(mparams) do 407 | if not match(mp, "^[%a_][%w_]*$") then 408 | wfatal("bad macro parameter name `"..mp.."'") 409 | end 410 | if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end 411 | mdup[mp] = true 412 | end 413 | -- Check for duplicate or recursive macro definitions. 414 | local opname = name.."_"..#mparams 415 | if map_op[opname] or map_op[name.."_*"] then 416 | wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") 417 | end 418 | if mac_capture then wfatal("recursive macro definition") end 419 | 420 | -- Enable statement capture. 421 | local lines = {} 422 | mac_lineno = g_lineno 423 | mac_name = name 424 | mac_capture = function(stmt) -- Statement capture function. 425 | -- Stop macro definition with .endmacro pseudo-opcode. 426 | if not match(stmt, "^%s*.endmacro%s*$") then 427 | lines[#lines+1] = stmt 428 | return 429 | end 430 | mac_capture = nil 431 | mac_lineno = nil 432 | mac_name = nil 433 | mac_list[#mac_list+1] = opname 434 | -- Add macro-op definition. 435 | map_op[opname] = function(params) 436 | if not params then return mparams, lines end 437 | -- Protect against recursive macro invocation. 438 | if mac_active[opname] then wfatal("recursive macro invocation") end 439 | mac_active[opname] = true 440 | -- Setup substitution map. 441 | local subst = {} 442 | for i,mp in ipairs(mparams) do subst[mp] = params[i] end 443 | local mcom 444 | if g_opt.maccomment and g_opt.comment then 445 | mcom = " MACRO "..name.." ("..#mparams..")" 446 | wcomment("{"..mcom) 447 | end 448 | -- Loop through all captured statements 449 | for _,stmt in ipairs(lines) do 450 | -- Substitute macro parameters. 451 | local st = gsub(stmt, "[%w_]+", subst) 452 | st = definesubst(st) 453 | st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. 454 | if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end 455 | -- Emit statement. Use a protected call for better diagnostics. 456 | local ok, err = pcall(dostmt, st) 457 | if not ok then 458 | -- Add the captured statement to the error. 459 | wprinterr(err, "\n", g_indent, "| ", stmt, 460 | "\t[MACRO ", name, " (", #mparams, ")]\n") 461 | end 462 | end 463 | if mcom then wcomment("}"..mcom) end 464 | mac_active[opname] = nil 465 | end 466 | end 467 | end 468 | 469 | -- An .endmacro pseudo-opcode outside of a macro definition is an error. 470 | map_coreop[".endmacro_0"] = function(params) 471 | wfatal(".endmacro without .macro") 472 | end 473 | 474 | -- Dump all macros and their contents (with -PP only). 475 | local function dumpmacros(out, lvl) 476 | sort(mac_list) 477 | out:write("Macros:\n") 478 | for _,opname in ipairs(mac_list) do 479 | local name = sub(opname, 1, -3) 480 | local params, lines = map_op[opname]() 481 | out:write(format(" %-20s %s\n", name, concat(params, ", "))) 482 | if lvl > 1 then 483 | for _,line in ipairs(lines) do 484 | out:write(" |", line, "\n") 485 | end 486 | out:write("\n") 487 | end 488 | end 489 | out:write("\n") 490 | end 491 | 492 | -- Check for unfinished macro definitions. 493 | local function checkmacros() 494 | if mac_capture then 495 | wprinterr(g_fname, ":", mac_lineno, 496 | ": error: unfinished .macro `", mac_name ,"'\n") 497 | end 498 | end 499 | 500 | ------------------------------------------------------------------------------ 501 | 502 | -- Support variables for captures. 503 | local cap_lineno, cap_name 504 | local cap_buffers = {} 505 | local cap_used = {} 506 | 507 | -- Start a capture. 508 | map_coreop[".capture_1"] = function(params) 509 | if not params then return "name" end 510 | wflush() 511 | local name = params[1] 512 | if not match(name, "^[%a_][%w_]*$") then 513 | wfatal("bad capture name `"..name.."'") 514 | end 515 | if cap_name then 516 | wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) 517 | end 518 | cap_name = name 519 | cap_lineno = g_lineno 520 | -- Create or continue a capture buffer and start the output line capture. 521 | local buf = cap_buffers[name] 522 | if not buf then buf = {}; cap_buffers[name] = buf end 523 | g_capbuffer = buf 524 | g_synclineno = 0 525 | end 526 | 527 | -- Stop a capture. 528 | map_coreop[".endcapture_0"] = function(params) 529 | wflush() 530 | if not cap_name then wfatal(".endcapture without a valid .capture") end 531 | cap_name = nil 532 | cap_lineno = nil 533 | g_capbuffer = nil 534 | g_synclineno = 0 535 | end 536 | 537 | -- Dump a capture buffer. 538 | map_coreop[".dumpcapture_1"] = function(params) 539 | if not params then return "name" end 540 | wflush() 541 | local name = params[1] 542 | if not match(name, "^[%a_][%w_]*$") then 543 | wfatal("bad capture name `"..name.."'") 544 | end 545 | cap_used[name] = true 546 | wline(function(out) 547 | local buf = cap_buffers[name] 548 | if buf then wdumplines(out, buf) end 549 | end) 550 | g_synclineno = 0 551 | end 552 | 553 | -- Dump all captures and their buffers (with -PP only). 554 | local function dumpcaptures(out, lvl) 555 | out:write("Captures:\n") 556 | for name,buf in pairs(cap_buffers) do 557 | out:write(format(" %-20s %4s)\n", name, "("..#buf)) 558 | if lvl > 1 then 559 | local bar = rep("=", 76) 560 | out:write(" ", bar, "\n") 561 | for _,line in ipairs(buf) do 562 | out:write(" ", line, "\n") 563 | end 564 | out:write(" ", bar, "\n\n") 565 | end 566 | end 567 | out:write("\n") 568 | end 569 | 570 | -- Check for unfinished or unused captures. 571 | local function checkcaptures() 572 | if cap_name then 573 | wprinterr(g_fname, ":", cap_lineno, 574 | ": error: unfinished .capture `", cap_name,"'\n") 575 | return 576 | end 577 | for name in pairs(cap_buffers) do 578 | if not cap_used[name] then 579 | wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") 580 | end 581 | end 582 | end 583 | 584 | ------------------------------------------------------------------------------ 585 | 586 | -- Sections names. 587 | local map_sections = {} 588 | 589 | -- Pseudo-opcode to define code sections. 590 | -- TODO: Data sections, BSS sections. Needs extra C code and API. 591 | map_coreop[".section_*"] = function(params) 592 | if not params then return "name..." end 593 | if #map_sections > 0 then werror("duplicate section definition") end 594 | wflush() 595 | for sn,name in ipairs(params) do 596 | local opname = "."..name.."_0" 597 | if not match(name, "^[%a][%w_]*$") or 598 | map_op[opname] or map_op["."..name.."_*"] then 599 | werror("bad section name `"..name.."'") 600 | end 601 | map_sections[#map_sections+1] = name 602 | wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) 603 | map_op[opname] = function(params) g_arch.section(sn-1) end 604 | end 605 | wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) 606 | end 607 | 608 | -- Dump all sections. 609 | local function dumpsections(out, lvl) 610 | out:write("Sections:\n") 611 | for _,name in ipairs(map_sections) do 612 | out:write(format(" %s\n", name)) 613 | end 614 | out:write("\n") 615 | end 616 | 617 | ------------------------------------------------------------------------------ 618 | 619 | -- Replacement for customized Lua, which lacks the package library. 620 | local prefix = "" 621 | if not require then 622 | function require(name) 623 | local fp = assert(io.open(prefix..name..".lua")) 624 | local s = fp:read("*a") 625 | assert(fp:close()) 626 | return assert(loadstring(s, "@"..name..".lua"))() 627 | end 628 | end 629 | 630 | -- Load architecture-specific module. 631 | local function loadarch(arch) 632 | if not match(arch, "^[%w_]+$") then return "bad arch name" end 633 | local ok, m_arch = pcall(require, "dasm_"..arch) 634 | if not ok then return "cannot load module: "..m_arch end 635 | g_arch = m_arch 636 | wflush = m_arch.passcb(wline, werror, wfatal, wwarn) 637 | m_arch.setup(arch, g_opt) 638 | map_op, map_def = m_arch.mergemaps(map_coreop, map_def) 639 | end 640 | 641 | -- Dump architecture description. 642 | function opt_map.dumparch(args) 643 | local name = optparam(args) 644 | if not g_arch then 645 | local err = loadarch(name) 646 | if err then opterror(err) end 647 | end 648 | 649 | local t = {} 650 | for name in pairs(map_coreop) do t[#t+1] = name end 651 | for name in pairs(map_op) do t[#t+1] = name end 652 | sort(t) 653 | 654 | local out = stdout 655 | local _arch = g_arch._info 656 | out:write(format("%s version %s, released %s, %s\n", 657 | _info.name, _info.version, _info.release, _info.url)) 658 | g_arch.dumparch(out) 659 | 660 | local pseudo = true 661 | out:write("Pseudo-Opcodes:\n") 662 | for _,sname in ipairs(t) do 663 | local name, nparam = match(sname, "^(.+)_([0-9%*])$") 664 | if name then 665 | if pseudo and sub(name, 1, 1) ~= "." then 666 | out:write("\nOpcodes:\n") 667 | pseudo = false 668 | end 669 | local f = map_op[sname] 670 | local s 671 | if nparam ~= "*" then nparam = nparam + 0 end 672 | if nparam == 0 then 673 | s = "" 674 | elseif type(f) == "string" then 675 | s = map_op[".template__"](nil, f, nparam) 676 | else 677 | s = f(nil, nparam) 678 | end 679 | if type(s) == "table" then 680 | for _,s2 in ipairs(s) do 681 | out:write(format(" %-12s %s\n", name, s2)) 682 | end 683 | else 684 | out:write(format(" %-12s %s\n", name, s)) 685 | end 686 | end 687 | end 688 | out:write("\n") 689 | exit(0) 690 | end 691 | 692 | -- Pseudo-opcode to set the architecture. 693 | -- Only initially available (map_op is replaced when called). 694 | map_op[".arch_1"] = function(params) 695 | if not params then return "name" end 696 | local err = loadarch(params[1]) 697 | if err then wfatal(err) end 698 | wline(format("#if DASM_VERSION != %d", _info.vernum)) 699 | wline('#error "Version mismatch between DynASM and included encoding engine"') 700 | wline("#endif") 701 | end 702 | 703 | -- Dummy .arch pseudo-opcode to improve the error report. 704 | map_coreop[".arch_1"] = function(params) 705 | if not params then return "name" end 706 | wfatal("duplicate .arch statement") 707 | end 708 | 709 | ------------------------------------------------------------------------------ 710 | 711 | -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. 712 | map_coreop[".nop_*"] = function(params) 713 | if not params then return "[ignored...]" end 714 | end 715 | 716 | -- Pseudo-opcodes to raise errors. 717 | map_coreop[".error_1"] = function(params) 718 | if not params then return "message" end 719 | werror(params[1]) 720 | end 721 | 722 | map_coreop[".fatal_1"] = function(params) 723 | if not params then return "message" end 724 | wfatal(params[1]) 725 | end 726 | 727 | -- Dump all user defined elements. 728 | local function dumpdef(out) 729 | local lvl = g_opt.dumpdef 730 | if lvl == 0 then return end 731 | dumpsections(out, lvl) 732 | dumpdefines(out, lvl) 733 | if g_arch then g_arch.dumpdef(out, lvl) end 734 | dumpmacros(out, lvl) 735 | dumpcaptures(out, lvl) 736 | end 737 | 738 | ------------------------------------------------------------------------------ 739 | 740 | -- Helper for splitstmt. 741 | local splitlvl 742 | 743 | local function splitstmt_one(c) 744 | if c == "(" then 745 | splitlvl = ")"..splitlvl 746 | elseif c == "[" then 747 | splitlvl = "]"..splitlvl 748 | elseif c == "{" then 749 | splitlvl = "}"..splitlvl 750 | elseif c == ")" or c == "]" or c == "}" then 751 | if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end 752 | splitlvl = sub(splitlvl, 2) 753 | elseif splitlvl == "" then 754 | return " \0 " 755 | end 756 | return c 757 | end 758 | 759 | -- Split statement into (pseudo-)opcode and params. 760 | local function splitstmt(stmt) 761 | -- Convert label with trailing-colon into .label statement. 762 | local label = match(stmt, "^%s*(.+):%s*$") 763 | if label then return ".label", {label} end 764 | 765 | -- Split at commas and equal signs, but obey parentheses and brackets. 766 | splitlvl = "" 767 | stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) 768 | if splitlvl ~= "" then werror("unbalanced () or []") end 769 | 770 | -- Split off opcode. 771 | local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") 772 | if not op then werror("bad statement syntax") end 773 | 774 | -- Split parameters. 775 | local params = {} 776 | for p in gmatch(other, "%s*(%Z+)%z?") do 777 | params[#params+1] = gsub(p, "%s+$", "") 778 | end 779 | if #params > 16 then werror("too many parameters") end 780 | 781 | params.op = op 782 | return op, params 783 | end 784 | 785 | -- Process a single statement. 786 | dostmt = function(stmt) 787 | -- Ignore empty statements. 788 | if match(stmt, "^%s*$") then return end 789 | 790 | -- Capture macro defs before substitution. 791 | if mac_capture then return mac_capture(stmt) end 792 | stmt = definesubst(stmt) 793 | 794 | -- Emit C code without parsing the line. 795 | if sub(stmt, 1, 1) == "|" then 796 | local tail = sub(stmt, 2) 797 | wflush() 798 | if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end 799 | return 800 | end 801 | 802 | -- Split into (pseudo-)opcode and params. 803 | local op, params = splitstmt(stmt) 804 | 805 | -- Get opcode handler (matching # of parameters or generic handler). 806 | local f = map_op[op.."_"..#params] or map_op[op.."_*"] 807 | if not f then 808 | if not g_arch then wfatal("first statement must be .arch") end 809 | -- Improve error report. 810 | for i=0,9 do 811 | if map_op[op.."_"..i] then 812 | werror("wrong number of parameters for `"..op.."'") 813 | end 814 | end 815 | werror("unknown statement `"..op.."'") 816 | end 817 | 818 | -- Call opcode handler or special handler for template strings. 819 | if type(f) == "string" then 820 | map_op[".template__"](params, f) 821 | else 822 | f(params) 823 | end 824 | end 825 | 826 | -- Process a single line. 827 | local function doline(line) 828 | if g_opt.flushline then wflush() end 829 | 830 | -- Assembler line? 831 | local indent, aline = match(line, "^(%s*)%|(.*)$") 832 | if not aline then 833 | -- No, plain C code line, need to flush first. 834 | wflush() 835 | wsync() 836 | wline(line, false) 837 | return 838 | end 839 | 840 | g_indent = indent -- Remember current line indentation. 841 | 842 | -- Emit C code (even from macros). Avoids echo and line parsing. 843 | if sub(aline, 1, 1) == "|" then 844 | if not mac_capture then 845 | wsync() 846 | elseif g_opt.comment then 847 | wsync() 848 | wcomment(aline) 849 | end 850 | dostmt(aline) 851 | return 852 | end 853 | 854 | -- Echo assembler line as a comment. 855 | if g_opt.comment then 856 | wsync() 857 | wcomment(aline) 858 | end 859 | 860 | -- Strip assembler comments. 861 | aline = gsub(aline, "//.*$", "") 862 | 863 | -- Split line into statements at semicolons. 864 | if match(aline, ";") then 865 | for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end 866 | else 867 | dostmt(aline) 868 | end 869 | end 870 | 871 | ------------------------------------------------------------------------------ 872 | 873 | -- Write DynASM header. 874 | local function dasmhead(out) 875 | out:write(format([[ 876 | /* 877 | ** This file has been pre-processed with DynASM. 878 | ** %s 879 | ** DynASM version %s, DynASM %s version %s 880 | ** DO NOT EDIT! The original file is in "%s". 881 | */ 882 | 883 | ]], _info.url, 884 | _info.version, g_arch._info.arch, g_arch._info.version, 885 | g_fname)) 886 | end 887 | 888 | -- Read input file. 889 | readfile = function(fin) 890 | g_indent = "" 891 | g_lineno = 0 892 | g_synclineno = -1 893 | 894 | -- Process all lines. 895 | for line in fin:lines() do 896 | g_lineno = g_lineno + 1 897 | g_curline = line 898 | local ok, err = pcall(doline, line) 899 | if not ok and wprinterr(err, "\n") then return true end 900 | end 901 | wflush() 902 | 903 | -- Close input file. 904 | assert(fin == stdin or fin:close()) 905 | end 906 | 907 | -- Write output file. 908 | local function writefile(outfile) 909 | local fout 910 | 911 | -- Open output file. 912 | if outfile == nil or outfile == "-" then 913 | fout = stdout 914 | else 915 | fout = assert(io.open(outfile, "w")) 916 | end 917 | 918 | -- Write all buffered lines 919 | wdumplines(fout, g_wbuffer) 920 | 921 | -- Close output file. 922 | assert(fout == stdout or fout:close()) 923 | 924 | -- Optionally dump definitions. 925 | dumpdef(fout == stdout and stderr or stdout) 926 | end 927 | 928 | -- Translate an input file to an output file. 929 | local function translate(infile, outfile) 930 | g_wbuffer = {} 931 | g_indent = "" 932 | g_lineno = 0 933 | g_synclineno = -1 934 | 935 | -- Put header. 936 | wline(dasmhead) 937 | 938 | -- Read input file. 939 | local fin 940 | if infile == "-" then 941 | g_fname = "(stdin)" 942 | fin = stdin 943 | else 944 | g_fname = infile 945 | fin = assert(io.open(infile, "r")) 946 | end 947 | readfile(fin) 948 | 949 | -- Check for errors. 950 | if not g_arch then 951 | wprinterr(g_fname, ":*: error: missing .arch directive\n") 952 | end 953 | checkconds() 954 | checkmacros() 955 | checkcaptures() 956 | 957 | if g_errcount ~= 0 then 958 | stderr:write(g_fname, ":*: info: ", g_errcount, " error", 959 | (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", 960 | " in input file -- no output file generated.\n") 961 | dumpdef(stderr) 962 | exit(1) 963 | end 964 | 965 | -- Write output file. 966 | writefile(outfile) 967 | end 968 | 969 | ------------------------------------------------------------------------------ 970 | 971 | -- Print help text. 972 | function opt_map.help() 973 | stdout:write("DynASM -- ", _info.description, ".\n") 974 | stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") 975 | stdout:write[[ 976 | 977 | Usage: dynasm [OPTION]... INFILE.dasc|- 978 | 979 | -h, --help Display this help text. 980 | -V, --version Display version and copyright information. 981 | 982 | -o, --outfile FILE Output file name (default is stdout). 983 | -I, --include DIR Add directory to the include search path. 984 | 985 | -c, --ccomment Use /* */ comments for assembler lines. 986 | -C, --cppcomment Use // comments for assembler lines (default). 987 | -N, --nocomment Suppress assembler lines in output. 988 | -M, --maccomment Show macro expansions as comments (default off). 989 | 990 | -L, --nolineno Suppress CPP line number information in output. 991 | -F, --flushline Flush action list for every line. 992 | 993 | -D NAME[=SUBST] Define a substitution. 994 | -U NAME Undefine a substitution. 995 | 996 | -P, --dumpdef Dump defines, macros, etc. Repeat for more output. 997 | -A, --dumparch ARCH Load architecture ARCH and dump description. 998 | ]] 999 | exit(0) 1000 | end 1001 | 1002 | -- Print version information. 1003 | function opt_map.version() 1004 | stdout:write(format("%s version %s, released %s\n%s\n\n%s", 1005 | _info.name, _info.version, _info.release, _info.url, _info.copyright)) 1006 | exit(0) 1007 | end 1008 | 1009 | -- Misc. options. 1010 | function opt_map.outfile(args) g_opt.outfile = optparam(args) end 1011 | function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end 1012 | function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end 1013 | function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end 1014 | function opt_map.nocomment() g_opt.comment = false end 1015 | function opt_map.maccomment() g_opt.maccomment = true end 1016 | function opt_map.nolineno() g_opt.cpp = false end 1017 | function opt_map.flushline() g_opt.flushline = true end 1018 | function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end 1019 | 1020 | ------------------------------------------------------------------------------ 1021 | 1022 | -- Short aliases for long options. 1023 | local opt_alias = { 1024 | h = "help", ["?"] = "help", V = "version", 1025 | o = "outfile", I = "include", 1026 | c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", 1027 | L = "nolineno", F = "flushline", 1028 | P = "dumpdef", A = "dumparch", 1029 | } 1030 | 1031 | -- Parse single option. 1032 | local function parseopt(opt, args) 1033 | opt_current = #opt == 1 and "-"..opt or "--"..opt 1034 | local f = opt_map[opt] or opt_map[opt_alias[opt]] 1035 | if not f then 1036 | opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") 1037 | end 1038 | f(args) 1039 | end 1040 | 1041 | -- Parse arguments. 1042 | local function parseargs(args) 1043 | -- Default options. 1044 | g_opt.comment = "//|" 1045 | g_opt.endcomment = "" 1046 | g_opt.cpp = true 1047 | g_opt.dumpdef = 0 1048 | g_opt.include = { "" } 1049 | 1050 | -- Process all option arguments. 1051 | args.argn = 1 1052 | repeat 1053 | local a = args[args.argn] 1054 | if not a then break end 1055 | local lopt, opt = match(a, "^%-(%-?)(.+)") 1056 | if not opt then break end 1057 | args.argn = args.argn + 1 1058 | if lopt == "" then 1059 | -- Loop through short options. 1060 | for o in gmatch(opt, ".") do parseopt(o, args) end 1061 | else 1062 | -- Long option. 1063 | parseopt(opt, args) 1064 | end 1065 | until false 1066 | 1067 | -- Check for proper number of arguments. 1068 | local nargs = #args - args.argn + 1 1069 | if nargs ~= 1 then 1070 | if nargs == 0 then 1071 | if g_opt.dumpdef > 0 then return dumpdef(stdout) end 1072 | end 1073 | opt_map.help() 1074 | end 1075 | 1076 | -- Translate a single input file to a single output file 1077 | -- TODO: Handle multiple files? 1078 | translate(args[args.argn], g_opt.outfile) 1079 | end 1080 | 1081 | ------------------------------------------------------------------------------ 1082 | 1083 | -- Add the directory dynasm.lua resides in to the Lua module search path. 1084 | local arg = arg 1085 | if arg and arg[0] then 1086 | prefix = match(arg[0], "^(.*[/\\])") 1087 | if package and prefix then package.path = prefix.."?.lua;"..package.path end 1088 | end 1089 | 1090 | -- Start DynASM. 1091 | parseargs{...} 1092 | 1093 | ------------------------------------------------------------------------------ 1094 | 1095 | -------------------------------------------------------------------------------- /interpreter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "util.h" 5 | 6 | void interpret(const char *const input) 7 | { 8 | // Initialize the tape with 30,000 zeroes. 9 | uint8_t tape[30000] = { 0 }; 10 | 11 | // Set the pointer to point at the left most cell of the tape. 12 | uint8_t *ptr = tape; 13 | 14 | char current_char; 15 | for (int i = 0; (current_char = input[i]) != '\0'; ++i) { 16 | switch (current_char) { 17 | case '>': 18 | ++ptr; 19 | break; 20 | case '<': 21 | --ptr; 22 | break; 23 | case '+': 24 | ++(*ptr); 25 | break; 26 | case '-': 27 | --(*ptr); 28 | break; 29 | case '.': 30 | putchar(*ptr); 31 | break; 32 | case ',': 33 | *ptr = getchar(); 34 | break; 35 | case '[': 36 | if (!(*ptr)) { 37 | int loop = 1; 38 | while (loop > 0) { 39 | current_char = input[++i]; 40 | if (current_char == ']') 41 | --loop; 42 | else if (current_char == '[') 43 | ++loop; 44 | } 45 | } 46 | break; 47 | case ']': 48 | if (*ptr) { 49 | int loop = 1; 50 | while (loop > 0) { 51 | current_char = input[--i]; 52 | if (current_char == '[') 53 | --loop; 54 | else if (current_char == ']') 55 | ++loop; 56 | } 57 | } 58 | break; 59 | } 60 | } 61 | } 62 | 63 | int main(int argc, char *argv[]) 64 | { 65 | if (argc != 2) err("Usage: interpreter "); 66 | char *file_contents = read_file(argv[1]); 67 | if (file_contents == NULL) err("Couldn't open file"); 68 | interpret(file_contents); 69 | free(file_contents); 70 | } 71 | -------------------------------------------------------------------------------- /jit-arm.dasc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | 4 | |.arch arm 5 | |.actionlist actions 6 | | 7 | |// Use r4 as our cell pointer. 8 | |// Since r4 is a callee-save register, it will be preserved 9 | |// across our calls to getchar and putchar. 10 | |.define PTR, r4 11 | 12 | #define Dst &state 13 | #define MAX_NESTING 256 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | if (argc < 2) err("Usage: jit-arm "); 18 | dasm_State *state; 19 | initjit(&state, actions); 20 | 21 | unsigned int maxpc = 0; 22 | int pcstack[MAX_NESTING]; 23 | int *top = pcstack, *limit = pcstack + MAX_NESTING; 24 | 25 | // Function prologue. 26 | | push {PTR, r5, r7, lr} 27 | | mov PTR, r0 28 | 29 | for (char *p = read_file(argv[1]); *p; p++) { 30 | switch (*p) { 31 | case '>': 32 | | add PTR, PTR, #1 33 | break; 34 | case '<': 35 | | sub PTR, PTR, #1 36 | break; 37 | case '+': 38 | | ldrb r5, [PTR] 39 | | add r5, r5, #1 40 | | strb r5, [PTR] 41 | break; 42 | case '-': 43 | | ldrb r5, [PTR] 44 | | sub r5, r5, #1 45 | | strb r5, [PTR] 46 | break; 47 | case '.': 48 | | mov r0, #1 // stdout 49 | | mov r1, PTR 50 | | mov r2, #1 51 | | mov r7, #4 // sys_write 52 | | svc #0 53 | break; 54 | case ',': 55 | | mov r0, #0 // stdin 56 | | mov r1, PTR 57 | | mov r2, #1 58 | | mov r7, #3 // sys_read 59 | | svc #0 60 | break; 61 | case '[': 62 | if (top == limit) err("Nesting too deep."); 63 | // Each loop gets two pclabels: at the beginning and end. 64 | // We store pclabel offsets in a stack to link the loop 65 | // begin and end together. 66 | maxpc += 2; // add two labels 67 | *top++ = maxpc; 68 | dasm_growpc(&state, maxpc); 69 | | ldrb r5, [PTR] 70 | | cmp r5, #0 71 | | beq =>(maxpc-2) 72 | |=>(maxpc-1): 73 | break; 74 | case ']': 75 | if (top == pcstack) err("Unmatched ']'"); 76 | top--; 77 | | ldrb r5, [PTR] 78 | | cmp r5, #0 79 | | bne =>(*top-1) 80 | |=>(*top-2): 81 | break; 82 | } 83 | } 84 | 85 | // Function epilogue. 86 | | pop {PTR, r5, r7, pc} 87 | 88 | void (*fptr)(char*) = jitcode(&state); 89 | char *mem = calloc(30000, 1); 90 | fptr(mem); 91 | free(mem); 92 | free_jitcode(fptr); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /jit-x64.dasc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | 4 | |.arch x64 5 | |.actionlist actions 6 | | 7 | |// Use rbx as our cell pointer. 8 | |// Since rbx is a callee-save register, it will be preserved 9 | |// across our calls to getchar and putchar. 10 | |.define PTR, rbx 11 | | 12 | |// Macro for calling a function. 13 | |// In cases where our target is <=2**32 away we can use 14 | |// | call &addr 15 | |// But since we don't know if it will be, we use this safe 16 | |// sequence instead. 17 | |.macro callp, addr 18 | | mov64 rax, (uintptr_t)addr 19 | | call rax 20 | |.endmacro 21 | 22 | #define Dst &state 23 | #define MAX_NESTING 256 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | if (argc < 2) err("Usage: jit-x64 "); 28 | dasm_State *state; 29 | initjit(&state, actions); 30 | 31 | unsigned int maxpc = 0; 32 | int pcstack[MAX_NESTING]; 33 | int *top = pcstack, *limit = pcstack + MAX_NESTING; 34 | 35 | // Function prologue. 36 | | push PTR 37 | | mov PTR, rdi // rdi store 1st argument 38 | 39 | for (char *p = read_file(argv[1]); *p; p++) { 40 | switch (*p) { 41 | case '>': 42 | | inc PTR 43 | break; 44 | case '<': 45 | | dec PTR 46 | break; 47 | case '+': 48 | | inc byte [PTR] 49 | break; 50 | case '-': 51 | | dec byte [PTR] 52 | break; 53 | case '.': 54 | | movzx edi, byte [PTR] 55 | | callp putchar 56 | break; 57 | case ',': 58 | | callp getchar 59 | | mov byte [PTR], al 60 | break; 61 | case '[': 62 | if (top == limit) err("Nesting too deep."); 63 | // Each loop gets two pclabels: at the beginning and end. 64 | // We store pclabel offsets in a stack to link the loop 65 | // begin and end together. 66 | maxpc += 2; 67 | *top++ = maxpc; 68 | dasm_growpc(&state, maxpc); 69 | | cmp byte [PTR], 0 70 | | je =>(maxpc-2) 71 | |=>(maxpc-1): 72 | break; 73 | case ']': 74 | if (top == pcstack) err("Unmatched ']'"); 75 | top--; 76 | | cmp byte [PTR], 0 77 | | jne =>(*top-1) 78 | |=>(*top-2): 79 | break; 80 | } 81 | } 82 | 83 | // Function epilogue. 84 | | pop PTR 85 | | ret 86 | 87 | void (*fptr)(char*) = jitcode(&state); 88 | char *mem = calloc(30000, 1); 89 | fptr(mem); 90 | free(mem); 91 | free_jitcode(fptr); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /jit-x86.dasc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | 4 | |.arch x86 5 | |.actionlist actions 6 | | 7 | |// Use ebx as our cell pointer. 8 | |// Since ebx is a callee-save register, it will be preserved 9 | |// across our calls to getchar and putchar. 10 | |.define PTR, ebx 11 | | 12 | 13 | #define Dst &state 14 | #define MAX_NESTING 256 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | if (argc < 2) err("Usage: jit-x86 "); 19 | dasm_State *state; 20 | initjit(&state, actions); 21 | 22 | unsigned int maxpc = 0; 23 | int pcstack[MAX_NESTING]; 24 | int *top = pcstack, *limit = pcstack + MAX_NESTING; 25 | 26 | // Function prologue. 27 | | push ebp 28 | | mov ebp, esp 29 | | sub esp, 8 30 | | mov [ebp - 4], PTR 31 | | mov eax, [ebp + 8] 32 | | mov PTR, eax 33 | 34 | for (char *p = read_file(argv[1]); *p; p++) { 35 | switch (*p) { 36 | case '>': 37 | | inc PTR 38 | break; 39 | case '<': 40 | | dec PTR 41 | break; 42 | case '+': 43 | | inc byte [PTR] 44 | break; 45 | case '-': 46 | | dec byte [PTR] 47 | break; 48 | case '.': 49 | | movzx eax, byte [PTR] 50 | | mov [esp], eax 51 | | call &putchar 52 | break; 53 | case ',': 54 | | call &getchar 55 | | mov byte [PTR], al 56 | break; 57 | case '[': 58 | if (top == limit) err("Nesting too deep."); 59 | // Each loop gets two pclabels: at the beginning and end. 60 | // We store pclabel offsets in a stack to link the loop 61 | // begin and end together. 62 | maxpc += 2; 63 | *top++ = maxpc; 64 | dasm_growpc(&state, maxpc); 65 | | cmp byte [PTR], 0 66 | | je =>(maxpc-2) 67 | |=>(maxpc-1): 68 | break; 69 | case ']': 70 | if (top == pcstack) err("Unmatched ']'"); 71 | top--; 72 | | cmp byte [PTR], 0 73 | | jne =>(*top-1) 74 | |=>(*top-2): 75 | break; 76 | } 77 | } 78 | 79 | // Function epilogue. 80 | | mov eax, [ebp - 4] 81 | | mov PTR, eax 82 | | leave 83 | | ret 84 | 85 | void (*fptr)(char*) = jitcode(&state); 86 | char *mem = calloc(30000, 1); 87 | fptr(mem); 88 | free(mem); 89 | free_jitcode(fptr); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /progs/echo.b: -------------------------------------------------------------------------------- 1 | +[>,.,.<] 2 | 3 | -------------------------------------------------------------------------------- /progs/hello.b: -------------------------------------------------------------------------------- 1 | ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>. -------------------------------------------------------------------------------- /progs/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 | -------------------------------------------------------------------------------- /progs/sierpinski.b: -------------------------------------------------------------------------------- 1 | [ This program prints Sierpinski triangle on 80-column display. ] 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 | * * * * * M a d e * B y : * N Y Y R I K K I * 2 0 0 2 * * * * * 34 | -------------------------------------------------------------------------------- /progs/test.b: -------------------------------------------------------------------------------- 1 | ++++++++++++++++++++++++++++++++++++++++++++++++. 2 | -------------------------------------------------------------------------------- /tests/bench.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import hashlib 4 | import subprocess 5 | import sys 6 | import os 7 | import time 8 | 9 | def get_output(program, stdin): 10 | p = subprocess.Popen([os.getenv('BF_RUN','./jit-x64'), program] + sys.argv[1:], stdout=subprocess.PIPE, stdin=subprocess.PIPE) 11 | start = time.time() 12 | output = p.communicate(input=stdin + '\x00')[0] 13 | return output, time.time() - start 14 | 15 | expected_output_hashes = { 16 | 'progs/mandelbrot.b': 'b77a017f811831f0b74e0d69c08b78e620dbda2b', 17 | 'progs/hanoi.b': '32cdfe329039ce63531dcd4b340df269d4fd8f7f', 18 | ('progs/awib.b', open('progs/awib.b').read()): '3b4f9a78ec3ee32e05969e108916a4affa0c2bba' 19 | } 20 | 21 | for filename, expected_hash in expected_output_hashes.iteritems(): 22 | stdin = '' 23 | if isinstance(filename, tuple): 24 | filename, stdin = filename 25 | output, elapsed = get_output(filename, stdin) 26 | actual_hash = hashlib.sha1(output).hexdigest() 27 | print filename.ljust(24), 28 | if actual_hash == expected_hash: 29 | print 'GOOD\t%.1fms' % (elapsed * 1000) 30 | else: 31 | print "bad output: expected %s got %s" % ( 32 | expected_hash, actual_hash) 33 | print output.decode('ascii', 'replace') 34 | -------------------------------------------------------------------------------- /tests/jit0-arm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | // Machine code for: 8 | // 000082e0
: 9 | // 82e0: e3a00000 mov r0, #0 10 | // 82e4: e12fff1e bx lr 11 | 12 | char code[] = { 13 | 0x00, 0x00, 0xa0, 0xe3, // 0xe3a00000 14 | 0x1e, 0xff, 0x2f, 0xe1 // 0xe12fff1e 15 | }; 16 | 17 | if (argc < 2) { 18 | fprintf(stderr, "Usage: jit0-arm \n"); 19 | return 1; 20 | } 21 | 22 | // Overwrite immediate value "0" in the instruction 23 | // with the user's value. This will make our code: 24 | // mov r0, 25 | // bx lr 26 | int num = atoi(argv[1]); 27 | memcpy(&code[0], &num, 2); 28 | 29 | // Allocate writable/executable memory. 30 | // Note: real programs should not map memory both writable 31 | // and executable because it is a security risk. 32 | void *mem = mmap(NULL, sizeof(code), PROT_WRITE | PROT_EXEC, 33 | MAP_ANON | MAP_PRIVATE, -1, 0); 34 | memcpy(mem, code, sizeof(code)); 35 | 36 | // Clear caches to prevent self-modifying code execute failed due to I-cache 37 | // and D-cache not coherent. 38 | // 39 | // Please see: 40 | // http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code 41 | #if defined(__GNUC__) 42 | __builtin___clear_cache((char*) mem, (char*) (mem + sizeof(code))); 43 | #else 44 | #error "Missing builtin to flush instruction cache." 45 | #endif 46 | 47 | // The function will return the user's value. 48 | int (*func)() = mem; 49 | return func(); 50 | } 51 | -------------------------------------------------------------------------------- /tests/jit0-x64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | // Machine code for: 8 | // mov eax, 0 9 | // ret 10 | unsigned char code[] = {0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3}; 11 | 12 | if (argc < 2) { 13 | fprintf(stderr, "Usage: jit0-x64 \n"); 14 | return 1; 15 | } 16 | 17 | // Overwrite immediate value "0" in the instruction 18 | // with the user's value. This will make our code: 19 | // mov eax, 20 | // ret 21 | int num = atoi(argv[1]); 22 | memcpy(&code[1], &num, 4); 23 | 24 | // Allocate writable/executable memory. 25 | // Note: real programs should not map memory both writable 26 | // and executable because it is a security risk. 27 | void *mem = mmap(NULL, sizeof(code), PROT_WRITE | PROT_EXEC, 28 | MAP_ANON | MAP_PRIVATE, -1, 0); 29 | memcpy(mem, code, sizeof(code)); 30 | 31 | // The function will return the user's value. 32 | int (*func)() = mem; 33 | return func(); 34 | } 35 | -------------------------------------------------------------------------------- /tests/test_stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | #define GUARD(expr) assert(!(expr)) 6 | 7 | int main () { 8 | struct stack stack = { .size = 0, .items = { 0 } }; 9 | 10 | puts("testing STACKSIZE"); 11 | assert(STACKSIZE == 100); 12 | 13 | puts("testing pushes"); 14 | GUARD(stack_push(&stack, 1)); 15 | assert(stack.size == 1); 16 | assert(stack.items != NULL); 17 | assert(stack.items[0] == 1); 18 | 19 | GUARD(stack_push(&stack, 2)); 20 | assert(stack.size == 2); 21 | assert(stack.items != NULL); 22 | assert(stack.items[0] == 1); 23 | assert(stack.items[1] == 2); 24 | 25 | puts("testing pops"); 26 | int x = 0; 27 | GUARD(stack_pop(&stack, &x)); 28 | assert(x == 2); 29 | assert(stack.size == 1); 30 | assert(stack.items != NULL); 31 | assert(stack.items[0] == 1); 32 | 33 | GUARD(stack_pop(&stack, &x)); 34 | assert(x == 1); 35 | assert(stack.size == 0); 36 | assert(stack.items != NULL); 37 | 38 | puts("testing excessive pops"); 39 | int rc = stack_pop(&stack, &x); 40 | assert(rc == -1); 41 | assert(x == 1); 42 | assert(stack.size == 0); 43 | assert(stack.items != NULL); 44 | 45 | puts("tests pass"); 46 | } 47 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // prints to stderr than exits with code 1 6 | static inline 7 | void err(const char * const msg) 8 | { 9 | fprintf(stderr, "%s\n", msg); 10 | exit(1); 11 | } 12 | 13 | // returns a heap allocated string, caller needs to free 14 | static inline 15 | char *read_file(const char * const filename) 16 | { 17 | if (filename == NULL) return NULL; 18 | 19 | FILE *fp = fopen(filename, "r"); 20 | if (fp == NULL) return NULL; 21 | 22 | assert(!fseek(fp, 0, SEEK_END)); 23 | long file_size = ftell(fp); 24 | rewind(fp); 25 | size_t code_size = sizeof(char) * file_size; 26 | char *code = malloc(code_size); 27 | if (code == NULL) return NULL; 28 | 29 | fread(code, 1, file_size, fp); 30 | assert(!fclose(fp)); 31 | return code; 32 | } 33 | 34 | #define STACKSIZE 100 35 | 36 | struct stack { 37 | int size; 38 | int items [STACKSIZE]; 39 | }; 40 | 41 | static inline 42 | int stack_push(struct stack * const p, const int x) 43 | { 44 | if (p->size == STACKSIZE) 45 | return -1; 46 | 47 | p->items[p->size++] = x; 48 | return 0; 49 | } 50 | 51 | static inline 52 | int stack_pop(struct stack * const p, int *x) 53 | { 54 | if (p->size == 0) 55 | return -1; 56 | 57 | *x = p->items[--p->size]; 58 | return 0; 59 | } 60 | --------------------------------------------------------------------------------