vm: remove old JIT
diff --git a/vm/Makefile b/vm/Makefile
index 3e180b9..a7b3f48 100644
--- a/vm/Makefile
+++ b/vm/Makefile
@@ -12,9 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-DYNASM := ../dynasm
-
-CFLAGS := -Wall -Werror -Iinc -I$(DYNASM) -O2 -g
+CFLAGS := -Wall -Werror -Iinc -O2 -g
LDLIBS := -lm
ifeq ($(COVERAGE),1)
@@ -29,9 +27,6 @@
all: libubpf.a test
-%.c: %.dasm minilua
- LUA_PATH=$(DYNASM)/?.lua ./minilua $(DYNASM)/dynasm.lua -o $@ $<
-
ubpf_jit_x86_64.o: ubpf_jit_x86_64.c ubpf_jit_x86_64.h
libubpf.a: ubpf_vm.o ubpf_jit_x86_64.o ubpf_loader.o
@@ -39,8 +34,5 @@
test: test.o libubpf.a
-minilua: ../luajit-2.0/src/host/minilua.c
- $(CC) -o $@ $< -lm
-
clean:
- rm -f test libubpf.a *.o ubpf_jit.c
+ rm -f test libubpf.a *.o
diff --git a/vm/ubpf_jit.dasm b/vm/ubpf_jit.dasm
deleted file mode 100644
index 4dcaa71..0000000
--- a/vm/ubpf_jit.dasm
+++ /dev/null
@@ -1,636 +0,0 @@
-// vi: ft=c
-/*
- * Copyright 2015 Big Switch Networks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <assert.h>
-#include "ubpf_int.h"
-
-#define DASM_CHECKS
-#include <dasm_proto.h>
-#include <dasm_x86.h>
-
-|.arch x64
-
-/* The hardcoded dasm_State variable name is confusing given our use of 'dst' */
-#define dasm Dst
-
-#define STACK_SIZE 128
-
-/*
- * Register mapping:
- *
- * eBPF -> x86
- * 0 -> rax
- * 1 -> rdi
- * 2 -> rsi
- * 3 -> rdx
- * 4 -> r9
- * 5 -> r8
- * 6 -> rbx
- * 7 -> r13
- * 8 -> r14
- * 9 -> r15
- * 10 -> rbp
- *
- * eBPF calling convention:
- * - Registers r6-r10 are callee save.
- * - Function call arguments go in r1-r5.
- * - Return value goes in r0.
- *
- * x86 calling convention:
- * - Registers rbp, rbx, r12, r13, r14, and r15 are callee save.
- * - Function call arguments go in rdi, rsi, rdx, rcx, r8, and r9.
- * - Return value goes in rax.
- *
- * rcx (cl) is a required operand for shifts by a register. We reserve it.
- * rsp could not be used for the stack pointer due to DynASM issues.
- * r12 could not be used due to DynASM issues.
- */
-#define RAX 0
-#define RCX 1
-#define RDX 2
-#define RBX 3
-#define RSP 4
-#define RBP 5
-#define RSI 6
-#define RDI 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-/* r12 is unused (encoding problems) */
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define REGISTER_MAP_SIZE 11
-static int register_map[REGISTER_MAP_SIZE] = {
- RAX,
- RDI,
- RSI,
- RDX,
- R9,
- R8,
- RBX,
- R13,
- R14,
- R15,
- RBP,
-};
-
-/* Return the x86 register for the given eBPF register */
-static int
-map_register(int r)
-{
- assert(r < REGISTER_MAP_SIZE);
- return register_map[r % REGISTER_MAP_SIZE];
-}
-
-/* For testing, this changes the mapping between x86 and eBPF registers */
-void
-ubpf_set_register_offset(int x)
-{
- int i;
- if (x < REGISTER_MAP_SIZE) {
- int tmp[REGISTER_MAP_SIZE];
- memcpy(tmp, register_map, sizeof(register_map));
- for (i = 0; i < REGISTER_MAP_SIZE; i++) {
- register_map[i] = tmp[(i+x)%REGISTER_MAP_SIZE];
- }
- } else {
- /* Shuffle array */
- unsigned int seed = x;
- for (i = 0; i < REGISTER_MAP_SIZE-1; i++) {
- int j = i + (rand_r(&seed) % (REGISTER_MAP_SIZE-i));
- int tmp = register_map[j];
- register_map[j] = register_map[i];
- register_map[i] = tmp;
- }
- }
-}
-
-static void muldivmod(dasm_State **dasm, uint16_t pc, uint8_t opcode, int src, int dst, int32_t imm);
-
-|.actionlist actions
-
-ubpf_jit_fn
-ubpf_compile(struct ubpf_vm *vm, char **errmsg)
-{
- dasm_State *d;
- void *jitted = NULL;
- size_t jitted_size;
- int ret;
-
- *errmsg = NULL;
-
- if (vm->jitted) {
- return vm->jitted;
- }
-
- if (!vm->insts) {
- *errmsg = ubpf_error("code has not been loaded into this VM");
- return NULL;
- }
-
- |.section code
- dasm_init(&d, DASM_MAXSECTION);
-
- |.globals lbl_
- void *labels[lbl__MAX];
- dasm_setupglobal(&d, labels, lbl__MAX);
-
- dasm_setup(&d, actions);
-
- dasm_growpc(&d, vm->num_insts);
-
- dasm_State **dasm = &d;
-
- if ((ret = dasm_checkstep(dasm, 0)) != DASM_S_OK) {
- *errmsg = ubpf_error("DynASM error %#x before prologue", ret);
- goto error;
- }
-
- /* Prologue */
- |.code
- |->entry:
- /* rbp, rbx, r13, r14, and r15 are callee save */
- /* TODO don't save registers we don't write to */
- | push rbp
- | push rbx
- | push r13
- | push r14
- | push r15
-
- /* Move rdi into register 1 */
- if (map_register(1) != RDI) {
- | mov Rq(map_register(1)), rdi
- }
-
- /* Allocate stack space and store address in r10 */
- | sub rsp, STACK_SIZE
- | mov Rq(map_register(10)), Rq(RSP)
-
- if ((ret = dasm_checkstep(dasm, 0)) != DASM_S_OK) {
- *errmsg = ubpf_error("DynASM error %#x after prologue", ret);
- goto error;
- }
-
- int i;
- for (i = 0; i < vm->num_insts; i++) {
- struct ebpf_inst inst = vm->insts[i];
- |=>i:
-
- int src = map_register(inst.src);
- int dst = map_register(inst.dst);
- int jmp_target = i + inst.offset + 1;
-
- switch (inst.opcode) {
- case EBPF_OP_ADD_IMM:
- | add Rd(dst), inst.imm
- break;
- case EBPF_OP_ADD_REG:
- | add Rd(dst), Rd(src)
- break;
- case EBPF_OP_SUB_IMM:
- | sub Rd(dst), inst.imm
- break;
- case EBPF_OP_SUB_REG:
- | sub Rd(dst), Rd(src)
- break;
- case EBPF_OP_MUL_IMM:
- case EBPF_OP_MUL_REG:
- case EBPF_OP_DIV_IMM:
- case EBPF_OP_DIV_REG:
- case EBPF_OP_MOD_IMM:
- case EBPF_OP_MOD_REG:
- muldivmod(dasm, i, inst.opcode, src, dst, inst.imm);
- break;
- case EBPF_OP_OR_IMM:
- | or Rd(dst), inst.imm
- break;
- case EBPF_OP_OR_REG:
- | or Rd(dst), Rd(src)
- break;
- case EBPF_OP_AND_IMM:
- | and Rd(dst), inst.imm
- break;
- case EBPF_OP_AND_REG:
- | and Rd(dst), Rd(src)
- break;
- case EBPF_OP_LSH_IMM:
- | shl Rd(dst), inst.imm
- break;
- case EBPF_OP_LSH_REG:
- | mov Rq(RCX), Rq(src)
- | shl Rd(dst), cl
- break;
- case EBPF_OP_RSH_IMM:
- | shr Rd(dst), inst.imm
- break;
- case EBPF_OP_RSH_REG:
- | mov Rq(RCX), Rq(src)
- | shr Rd(dst), cl
- break;
- case EBPF_OP_NEG:
- | neg Rd(dst)
- break;
- case EBPF_OP_XOR_IMM:
- | xor Rd(dst), inst.imm
- break;
- case EBPF_OP_XOR_REG:
- | xor Rd(dst), Rd(src)
- break;
- case EBPF_OP_MOV_IMM:
- | mov Rd(dst), inst.imm
- break;
- case EBPF_OP_MOV_REG:
- | mov Rd(dst), Rd(src)
- break;
- case EBPF_OP_ARSH_IMM:
- | sar Rd(dst), inst.imm
- break;
- case EBPF_OP_ARSH_REG:
- | mov Rq(RCX), Rq(src)
- | sar Rd(dst), cl
- break;
-
- case EBPF_OP_LE:
- /* No-op */
- break;
- case EBPF_OP_BE:
- if (inst.imm == 16) {
- | rol Rw(dst), 8
- | and Rd(dst), 0xffff
- } else if (inst.imm == 32) {
- /* bswap of r8d+ is misassembled */
- if (dst < 8) {
- | bswap Rd(dst)
- } else {
- | mov Rq(RCX), Rq(dst)
- | bswap ecx
- | mov Rd(dst), ecx
- }
- } else if (inst.imm == 64) {
- /* bswap of r8+ is misassembled */
- if (dst < 8) {
- | bswap Rq(dst)
- } else {
- | mov Rq(RCX), Rq(dst)
- | bswap rcx
- | mov Rq(dst), rcx
- }
- }
- break;
-
- case EBPF_OP_ADD64_IMM:
- | add Rq(dst), inst.imm
- break;
- case EBPF_OP_ADD64_REG:
- | add Rq(dst), Rq(src)
- break;
- case EBPF_OP_SUB64_IMM:
- | sub Rq(dst), inst.imm
- break;
- case EBPF_OP_SUB64_REG:
- | sub Rq(dst), Rq(src)
- break;
- case EBPF_OP_MUL64_IMM:
- case EBPF_OP_MUL64_REG:
- case EBPF_OP_DIV64_IMM:
- case EBPF_OP_DIV64_REG:
- case EBPF_OP_MOD64_IMM:
- case EBPF_OP_MOD64_REG:
- muldivmod(dasm, i, inst.opcode, src, dst, inst.imm);
- break;
- case EBPF_OP_OR64_IMM:
- | or Rq(dst), inst.imm
- break;
- case EBPF_OP_OR64_REG:
- | or Rq(dst), Rq(src)
- break;
- case EBPF_OP_AND64_IMM:
- | and Rq(dst), inst.imm
- break;
- case EBPF_OP_AND64_REG:
- | and Rq(dst), Rq(src)
- break;
- case EBPF_OP_LSH64_IMM:
- | shl Rq(dst), inst.imm
- break;
- case EBPF_OP_LSH64_REG:
- | mov Rq(RCX), Rq(src)
- | shl Rq(dst), cl
- break;
- case EBPF_OP_RSH64_IMM:
- | shr Rq(dst), inst.imm
- break;
- case EBPF_OP_RSH64_REG:
- | mov Rq(RCX), Rq(src)
- | shr Rq(dst), cl
- break;
- case EBPF_OP_NEG64:
- | neg Rq(dst)
- break;
- case EBPF_OP_XOR64_IMM:
- | xor Rq(dst), inst.imm
- break;
- case EBPF_OP_XOR64_REG:
- | xor Rq(dst), Rq(src)
- break;
- case EBPF_OP_MOV64_IMM:
- /* TODO use shorter mov for smaller immediates */
- | mov Rq(dst), inst.imm
- break;
- case EBPF_OP_MOV64_REG:
- | mov Rq(dst), Rq(src)
- break;
- case EBPF_OP_ARSH64_IMM:
- | sar Rq(dst), inst.imm
- break;
- case EBPF_OP_ARSH64_REG:
- | mov Rq(RCX), Rq(src)
- | sar Rq(dst), cl
- break;
-
- case EBPF_OP_JA:
- | jmp =>jmp_target
- break;
- case EBPF_OP_JEQ_IMM:
- | cmp Rq(dst), inst.imm
- | je =>jmp_target
- break;
- case EBPF_OP_JEQ_REG:
- | cmp Rq(dst), Rq(src)
- | je =>jmp_target
- break;
- case EBPF_OP_JGT_IMM:
- | cmp Rq(dst), inst.imm
- | ja =>jmp_target
- break;
- case EBPF_OP_JGT_REG:
- | cmp Rq(dst), Rq(src)
- | ja =>jmp_target
- break;
- case EBPF_OP_JGE_IMM:
- | cmp Rq(dst), inst.imm
- | jae =>jmp_target
- break;
- case EBPF_OP_JGE_REG:
- | cmp Rq(dst), Rq(src)
- | jae =>jmp_target
- break;
- case EBPF_OP_JSET_IMM:
- | test Rq(dst), inst.imm
- | jnz =>jmp_target
- break;
- case EBPF_OP_JSET_REG:
- | test Rq(dst), Rq(src)
- | jnz =>jmp_target
- break;
- case EBPF_OP_JNE_IMM:
- | cmp Rq(dst), inst.imm
- | jne =>jmp_target
- break;
- case EBPF_OP_JNE_REG:
- | cmp Rq(dst), Rq(src)
- | jne =>jmp_target
- break;
- case EBPF_OP_JSGT_IMM:
- | cmp Rq(dst), inst.imm
- | jg =>jmp_target
- break;
- case EBPF_OP_JSGT_REG:
- | cmp Rq(dst), Rq(src)
- | jg =>jmp_target
- break;
- case EBPF_OP_JSGE_IMM:
- | cmp Rq(dst), inst.imm
- | jge =>jmp_target
- break;
- case EBPF_OP_JSGE_REG:
- | cmp Rq(dst), Rq(src)
- | jge =>jmp_target
- break;
- case EBPF_OP_CALL:
- /* We reserve RCX for shifts */
- | mov rcx, r9
- /* TODO direct call */
- | mov rax, vm->ext_funcs[inst.imm]
- | call rax
- break;
- case EBPF_OP_EXIT:
- if (i != vm->num_insts - 1) {
- | jmp ->exit
- }
- break;
-
- case EBPF_OP_LDXW:
- | mov Rd(dst), dword [Rq(src)+inst.offset]
- break;
- case EBPF_OP_LDXH:
- /* movzx is not assembled correctly */
- | xor ecx, ecx
- | mov cx, word [Rq(src)+inst.offset]
- | mov Rq(dst), Rq(RCX)
- break;
- case EBPF_OP_LDXB:
- /* movzx is not assembled correctly */
- | xor ecx, ecx
- | mov cl, byte [Rq(src)+inst.offset]
- | mov Rq(dst), Rq(RCX)
- break;
- case EBPF_OP_LDXDW:
- | mov Rq(dst), qword [Rq(src)+inst.offset]
- break;
-
- case EBPF_OP_STW:
- | mov dword [Rq(dst)+inst.offset], inst.imm
- break;
- case EBPF_OP_STH:
- | mov word [Rq(dst)+inst.offset], inst.imm
- break;
- case EBPF_OP_STB:
- | mov byte [Rq(dst)+inst.offset], inst.imm
- break;
- case EBPF_OP_STDW:
- | mov qword [Rq(dst)+inst.offset], inst.imm
- break;
-
- case EBPF_OP_STXW:
- | mov dword [Rq(dst)+inst.offset], Rd(src)
- break;
- case EBPF_OP_STXH:
- | mov word [Rq(dst)+inst.offset], Rw(src)
- break;
- case EBPF_OP_STXB:
- /* Rb(src) generates the wrong byte registers */
- /* mov rcx, Rq(src) also did not work */
- | mov Rq(RCX), Rq(src)
- | mov byte [Rq(dst)+inst.offset], cl
- break;
- case EBPF_OP_STXDW:
- | mov qword [Rq(dst)+inst.offset], Rq(src)
- break;
-
- case EBPF_OP_LDDW: {
- struct ebpf_inst inst2 = vm->insts[++i];
- uint64_t imm = (uint32_t)inst.imm | ((uint64_t)inst2.imm << 32);
- | mov64 Rq(dst), imm
- break;
- }
-
- }
-
- if ((ret = dasm_checkstep(dasm, 0)) != DASM_S_OK) {
- *errmsg = ubpf_error("DynASM error %#x at PC %d: opcode %02x src %u dst %u", ret, i, inst.opcode, src, dst);
- goto error;
- }
- }
-
- /* Epilogue */
- | ->exit:
- /* Move register 0 into rax */
- if (map_register(0) != RAX) {
- | mov Rq(RAX), Rq(map_register(0))
- }
- | ->exit2:
- | add rsp, STACK_SIZE
- | pop r15
- | pop r14
- | pop r13
- | pop rbx
- | pop rbp
- | ret
-
- /* Division by zero handler */
- const char *div_by_zero_fmt = "uBPF error: division by zero at PC %u\n";
- | ->div_by_zero:
- | mov64 rdi, (uintptr_t)stderr
- | mov64 rsi, (uintptr_t)div_by_zero_fmt
- | mov64 rax, (uintptr_t)fprintf
- | call rax
- | mov rax, -1
- | jmp ->exit2
-
- if ((ret = dasm_checkstep(dasm, 0)) != DASM_S_OK) {
- *errmsg = ubpf_error("DynASM error %#x after epilogue", ret);
- goto error;
- }
-
- if ((ret = dasm_link(dasm, &jitted_size)) != DASM_S_OK) {
- *errmsg = ubpf_error("internal uBPF error: dasm_link failed: %d", ret);
- goto error;
- }
-
- jitted = mmap(0, jitted_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (jitted == MAP_FAILED) {
- *errmsg = ubpf_error("internal uBPF error: mmap failed: %s\n", strerror(errno));
- goto error;
- }
-
- if ((ret = dasm_encode(dasm, jitted)) != DASM_S_OK) {
- *errmsg = ubpf_error("internal uBPF error: dasm_encode failed: %d\n", ret);
- goto error;
- }
-
- if (mprotect(jitted, jitted_size, PROT_READ | PROT_EXEC) < 0) {
- *errmsg = ubpf_error("internal uBPF error: mprotect failed: %s\n", strerror(errno));
- goto error;
- }
-
- assert(labels[lbl_entry] == jitted);
-
- dasm_free(dasm);
- vm->jitted = labels[lbl_entry];
- vm->jitted_size = jitted_size;
- return vm->jitted;
-
-error:
- dasm_free(dasm);
- if (jitted) {
- munmap(jitted, jitted_size);
- }
- return NULL;
-}
-
-static void
-muldivmod(dasm_State **dasm, uint16_t pc, uint8_t opcode, int src, int dst, int32_t imm)
-{
- bool mul = (opcode & EBPF_ALU_OP_MASK) == (EBPF_OP_MUL_IMM & EBPF_ALU_OP_MASK);
- bool div = (opcode & EBPF_ALU_OP_MASK) == (EBPF_OP_DIV_IMM & EBPF_ALU_OP_MASK);
- bool mod = (opcode & EBPF_ALU_OP_MASK) == (EBPF_OP_MOD_IMM & EBPF_ALU_OP_MASK);
- bool is64 = (opcode & EBPF_CLS_MASK) == EBPF_CLS_ALU64;
-
- if (div || mod) {
- if (is64) {
- | test Rq(src), Rq(src)
- } else {
- | test Rd(src), Rd(src)
- }
- | jnz >1
- | mov rdx, pc
- | jmp ->div_by_zero
- |1:
- }
-
- if (dst != RAX) {
- | push rax
- }
- if (dst != RDX) {
- | push rdx
- }
- if (imm) {
- | mov Rq(RCX), imm
- } else {
- | mov Rq(RCX), Rq(src)
- }
- | mov Rq(RAX), Rq(dst)
- if (div || mod) {
- | xor edx, edx
- if (is64) {
- | div rcx
- } else {
- | div ecx
- }
- } else {
- if (is64) {
- | mul rcx
- } else {
- | mul ecx
- }
- }
- if (dst != RDX) {
- if (mod) {
- | mov Rq(dst), Rq(RDX)
- }
- | pop rdx
- }
- if (dst != RAX) {
- if (div || mul) {
- | mov Rq(dst), Rq(RAX)
- }
- | pop rax
- }
-}