nit fixes
This commit is contained in:
parent
74e6500bf1
commit
85a67caaa7
2
Makefile
2
Makefile
|
@ -175,7 +175,7 @@ build/v86-debug.wasm: src/native/*.c src/native/*.h src/native/codegen/*.c src/n
|
|||
|
||||
build/codegen-test.wasm: src/native/*.c src/native/*.h src/native/codegen/*.c src/native/codegen/*.h
|
||||
mkdir -p build
|
||||
emcc src/native/codegen/api.c src/native/codegen/codegen.c \
|
||||
emcc src/native/codegen/codegen.c \
|
||||
-Isrc/native/ \
|
||||
-Wall -Wpedantic -Wextra \
|
||||
-Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \
|
||||
|
|
|
@ -1,339 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "const.h"
|
||||
#include "wasm_opcodes.h"
|
||||
#include "util.h"
|
||||
#include "codegen.h"
|
||||
#include "wasm_util.h"
|
||||
|
||||
// location in memory where we store the result of the computation for testing
|
||||
#define RESULT_LOC 1600
|
||||
|
||||
extern bool is_asize_32(void);
|
||||
extern int32_t read_imm8();
|
||||
extern int32_t read_imm8s();
|
||||
extern int32_t read_imm16();
|
||||
extern int32_t read_imm32s();
|
||||
extern int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index);
|
||||
|
||||
extern int32_t* const instruction_pointer;
|
||||
extern int32_t* const previous_ip;
|
||||
extern uint8_t* const reg8;
|
||||
extern uint16_t* const reg16;
|
||||
extern int8_t* const reg8s;
|
||||
extern int16_t* const reg16s;
|
||||
extern int32_t* const reg32s;
|
||||
extern Writer cs;
|
||||
|
||||
static void jit_resolve_modrm32_(int32_t);
|
||||
static void jit_resolve_modrm16_(int32_t);
|
||||
|
||||
void gen_increment_instruction_pointer(int32_t n)
|
||||
{
|
||||
push_i32(&cs, (int32_t)instruction_pointer); // store address of ip
|
||||
|
||||
load_i32(&cs, (int32_t)instruction_pointer); // load ip
|
||||
push_i32(&cs, n); // load value to add to it
|
||||
add_i32(&cs);
|
||||
|
||||
store_i32(&cs); // store it back in
|
||||
}
|
||||
|
||||
void gen_set_previous_eip()
|
||||
{
|
||||
push_i32(&cs, (int32_t)previous_ip); // store address of previous ip
|
||||
load_i32(&cs, (int32_t)instruction_pointer); // load ip
|
||||
store_i32(&cs); // store it as previous ip
|
||||
}
|
||||
|
||||
void gen_fn0(char* fn, uint8_t fn_len)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN0_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_fn1(char* fn, uint8_t fn_len, int32_t arg0)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_TYPE_INDEX);
|
||||
push_i32(&cs, arg0);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_fn2(char* fn, uint8_t fn_len, int32_t arg0, int32_t arg1)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_TYPE_INDEX);
|
||||
push_i32(&cs, arg0);
|
||||
push_i32(&cs, arg1);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_drop()
|
||||
{
|
||||
write_raw_u8(&cs, OP_DROP);
|
||||
}
|
||||
|
||||
#define MODRM_ENTRY(n, work)\
|
||||
case (n) | 0 << 3:\
|
||||
case (n) | 1 << 3:\
|
||||
case (n) | 2 << 3:\
|
||||
case (n) | 3 << 3:\
|
||||
case (n) | 4 << 3:\
|
||||
case (n) | 5 << 3:\
|
||||
case (n) | 6 << 3:\
|
||||
case (n) | 7 << 3:\
|
||||
work; break;
|
||||
|
||||
#define MODRM_ENTRY16_0(row, seg, reg1, reg2)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm_entry_0(seg, reg1, reg2, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm_entry_0(seg, reg1, reg2, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm_entry_0(seg, reg1, reg2, read_imm16()))
|
||||
|
||||
#define MODRM_ENTRY16_1(row, seg, reg)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm_entry_1(seg, reg, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm_entry_1(seg, reg, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm_entry_1(seg, reg, read_imm16()))
|
||||
|
||||
static void inline gen_modrm_entry_0(int32_t fn_idx, int32_t reg16_idx_1, int32_t reg16_idx_2, int32_t imm)
|
||||
{
|
||||
// generates: fn( ( reg1 + reg2 + imm ) & 0xFFFF )
|
||||
load_u16(&cs, reg16_idx_1);
|
||||
load_u16(&cs, reg16_idx_2);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, 0xFFFF);
|
||||
and_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void gen_modrm_entry_1(int32_t fn_idx, int32_t reg16_idx, int32_t imm)
|
||||
{
|
||||
// generates: fn ( ( reg + imm ) & 0xFFFF )
|
||||
load_u16(&cs, reg16_idx);
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, 0xFFFF);
|
||||
and_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void jit_resolve_modrm16_(int32_t modrm_byte)
|
||||
{
|
||||
int32_t const ds = fn_get_seg_prefix_ds_idx;
|
||||
int32_t const ss = fn_get_seg_prefix_ss_idx;
|
||||
|
||||
switch(modrm_byte)
|
||||
{
|
||||
// The following casts cause some weird issue with emscripten and cause
|
||||
// a performance hit. XXX: look into this later.
|
||||
MODRM_ENTRY16_0(0, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_0(1, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + DI))
|
||||
MODRM_ENTRY16_0(2, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_0(3, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + DI))
|
||||
MODRM_ENTRY16_1(4, ds, (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_1(5, ds, (int32_t)(reg16 + DI))
|
||||
|
||||
// special case
|
||||
MODRM_ENTRY(0x00 | 6, call_fn_with_arg(&cs, ds, read_imm16()))
|
||||
MODRM_ENTRY(0x40 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm8s()))
|
||||
MODRM_ENTRY(0x80 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm16()))
|
||||
|
||||
MODRM_ENTRY16_1(7, ds, (int32_t)(reg16 + BX))
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_resolve_modrm16(int32_t modrm_byte)
|
||||
{
|
||||
push_u32(&cs, RESULT_LOC);
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
store_i32(&cs);
|
||||
}
|
||||
|
||||
#define MODRM_ENTRY32_0(row, seg, reg)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm32_entry(seg, reg, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm32_entry(seg, reg, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm32_entry(seg, reg, read_imm32s()))
|
||||
|
||||
static void gen_modrm32_entry(int32_t fn_idx, int32_t reg32s_idx, int32_t imm)
|
||||
{
|
||||
// generates: fn ( reg + imm )
|
||||
load_i32(&cs, reg32s_idx);
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void jit_resolve_sib(bool mod)
|
||||
{
|
||||
uint8_t sib_byte = read_imm8();
|
||||
uint8_t r = sib_byte & 7;
|
||||
uint8_t m = sib_byte >> 3 & 7;
|
||||
|
||||
int32_t base_addr;
|
||||
int32_t base;
|
||||
uint8_t seg;
|
||||
bool base_is_mem_access = true;
|
||||
|
||||
if(r == 4)
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + ESP);
|
||||
seg = SS;
|
||||
}
|
||||
else if(r == 5)
|
||||
{
|
||||
if(mod)
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + EBP);
|
||||
seg = SS;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = read_imm32s();
|
||||
seg = DS;
|
||||
base_is_mem_access = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + r);
|
||||
seg = DS;
|
||||
}
|
||||
|
||||
// generate: get_seg_prefix(seg) + base
|
||||
// Where base is accessed from memory if base_is_mem_access or written as a constant otherwise
|
||||
|
||||
dbg_assert(seg < 16);
|
||||
write_raw_u8(&cs, OP_I32CONST);
|
||||
write_raw_u8(&cs, seg);
|
||||
|
||||
call_fn(&cs, fn_get_seg_prefix_idx);
|
||||
|
||||
if(base_is_mem_access)
|
||||
{
|
||||
load_i32(&cs, base_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
push_i32(&cs, base);
|
||||
}
|
||||
|
||||
add_i32(&cs);
|
||||
|
||||
// We now have to generate an offset value to add
|
||||
|
||||
if(m == 4)
|
||||
{
|
||||
// offset is 0, we don't need to add anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Offset is reg32s[m] << s, where s is:
|
||||
|
||||
uint8_t s = sib_byte >> 6 & 3;
|
||||
|
||||
load_i32(&cs, (int32_t)(reg32s + m));
|
||||
// We don't use push_u32 here either since s will fit in 1 byte
|
||||
write_raw_u8(&cs, OP_I32CONST);
|
||||
write_raw_u8(&cs, s);
|
||||
shl_i32(&cs);
|
||||
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void modrm32_special_case_1()
|
||||
{
|
||||
jit_resolve_sib(true);
|
||||
push_i32(&cs, read_imm8s());
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void modrm32_special_case_2()
|
||||
{
|
||||
jit_resolve_sib(true);
|
||||
push_i32(&cs, read_imm32s());
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void jit_resolve_modrm32_(int32_t modrm_byte)
|
||||
{
|
||||
int32_t const ds = fn_get_seg_prefix_ds_idx;
|
||||
int32_t const ss = fn_get_seg_prefix_ss_idx;
|
||||
|
||||
switch(modrm_byte)
|
||||
{
|
||||
MODRM_ENTRY32_0(0, ds, (int32_t)(reg32s + EAX))
|
||||
MODRM_ENTRY32_0(1, ds, (int32_t)(reg32s + ECX))
|
||||
MODRM_ENTRY32_0(2, ds, (int32_t)(reg32s + EDX))
|
||||
MODRM_ENTRY32_0(3, ds, (int32_t)(reg32s + EBX))
|
||||
|
||||
// special cases
|
||||
MODRM_ENTRY(0x00 | 4, jit_resolve_sib(false))
|
||||
MODRM_ENTRY(0x40 | 4, modrm32_special_case_1())
|
||||
MODRM_ENTRY(0x80 | 4, modrm32_special_case_2())
|
||||
MODRM_ENTRY(0x00 | 5, call_fn_with_arg(&cs, ds, read_imm32s()))
|
||||
MODRM_ENTRY(0x40 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm8s()))
|
||||
MODRM_ENTRY(0x80 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm32s()))
|
||||
|
||||
MODRM_ENTRY32_0(6, ds, (int32_t)(reg32s + ESI))
|
||||
MODRM_ENTRY32_0(7, ds, (int32_t)(reg32s + EDI))
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_resolve_modrm32(int32_t modrm_byte)
|
||||
{
|
||||
push_i32(&cs, RESULT_LOC);
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
store_i32(&cs);
|
||||
}
|
||||
|
||||
#undef MODRM_ENTRY
|
||||
|
||||
void gen_modrm_fn1(char* fn, uint8_t fn_len, int32_t modrm_byte, int32_t arg0)
|
||||
{
|
||||
// generates: fn( modrm_resolve( modrm_byte ), arg0 )
|
||||
if(is_asize_32())
|
||||
{
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
}
|
||||
|
||||
push_i32(&cs, arg0);
|
||||
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_RET_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte)
|
||||
{
|
||||
// generates: fn( modrm_resolve( modrm_byte ) )
|
||||
if(is_asize_32())
|
||||
{
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
}
|
||||
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_RET_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
|
@ -7,14 +7,35 @@
|
|||
#include "wasm_opcodes.h"
|
||||
#include "codegen.h"
|
||||
#include "util.h"
|
||||
#include "wasm_util.h"
|
||||
#include "module_init.h"
|
||||
|
||||
static Writer op = { .start = (uint8_t* const) 2048, .ptr = (uint8_t*) 2048, .len = 1024 };
|
||||
Writer cs = { .start = (uint8_t* const) 3072, .ptr = (uint8_t*) 3072, .len = 1024 };
|
||||
static Buffer op = { .start = (uint8_t* const) 2048, .ptr = (uint8_t*) 2048, .len = 1024 };
|
||||
static Buffer cs = { .start = (uint8_t* const) 3072, .ptr = (uint8_t*) 3072, .len = 1024 };
|
||||
|
||||
// location in memory where we store the result of the computation for testing
|
||||
#define RESULT_LOC 1600
|
||||
|
||||
extern bool is_asize_32(void);
|
||||
extern int32_t read_imm8();
|
||||
extern int32_t read_imm8s();
|
||||
extern int32_t read_imm16();
|
||||
extern int32_t read_imm32s();
|
||||
extern int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index);
|
||||
|
||||
extern int32_t* const instruction_pointer;
|
||||
extern int32_t* const previous_ip;
|
||||
extern uint8_t* const reg8;
|
||||
extern uint16_t* const reg16;
|
||||
extern int8_t* const reg8s;
|
||||
extern int16_t* const reg16s;
|
||||
extern int32_t* const reg32s;
|
||||
|
||||
static uint8_t* op_ptr_reset_location;
|
||||
static uint32_t import_table_size_reset_value;
|
||||
static uint32_t initial_import_count;
|
||||
static void jit_resolve_modrm32_(int32_t);
|
||||
static void jit_resolve_modrm16_(int32_t);
|
||||
|
||||
void gen_init()
|
||||
{
|
||||
|
@ -94,3 +115,309 @@ uintptr_t gen_get_final_offset()
|
|||
return (uintptr_t) op.ptr;
|
||||
}
|
||||
|
||||
void gen_increment_instruction_pointer(int32_t n)
|
||||
{
|
||||
push_i32(&cs, (int32_t)instruction_pointer); // store address of ip
|
||||
|
||||
load_i32(&cs, (int32_t)instruction_pointer); // load ip
|
||||
push_i32(&cs, n); // load value to add to it
|
||||
add_i32(&cs);
|
||||
|
||||
store_i32(&cs); // store it back in
|
||||
}
|
||||
|
||||
void gen_set_previous_eip()
|
||||
{
|
||||
push_i32(&cs, (int32_t)previous_ip); // store address of previous ip
|
||||
load_i32(&cs, (int32_t)instruction_pointer); // load ip
|
||||
store_i32(&cs); // store it as previous ip
|
||||
}
|
||||
|
||||
void gen_fn0(char* fn, uint8_t fn_len)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN0_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_fn1(char* fn, uint8_t fn_len, int32_t arg0)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_TYPE_INDEX);
|
||||
push_i32(&cs, arg0);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_fn2(char* fn, uint8_t fn_len, int32_t arg0, int32_t arg1)
|
||||
{
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_TYPE_INDEX);
|
||||
push_i32(&cs, arg0);
|
||||
push_i32(&cs, arg1);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_drop()
|
||||
{
|
||||
write_raw_u8(&cs, OP_DROP);
|
||||
}
|
||||
|
||||
#define MODRM_ENTRY(n, work)\
|
||||
case (n) | 0 << 3:\
|
||||
case (n) | 1 << 3:\
|
||||
case (n) | 2 << 3:\
|
||||
case (n) | 3 << 3:\
|
||||
case (n) | 4 << 3:\
|
||||
case (n) | 5 << 3:\
|
||||
case (n) | 6 << 3:\
|
||||
case (n) | 7 << 3:\
|
||||
work; break;
|
||||
|
||||
#define MODRM_ENTRY16_0(row, seg, reg1, reg2)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm_entry_0(seg, reg1, reg2, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm_entry_0(seg, reg1, reg2, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm_entry_0(seg, reg1, reg2, read_imm16()))
|
||||
|
||||
#define MODRM_ENTRY16_1(row, seg, reg)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm_entry_1(seg, reg, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm_entry_1(seg, reg, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm_entry_1(seg, reg, read_imm16()))
|
||||
|
||||
static void inline gen_modrm_entry_0(int32_t fn_idx, int32_t reg16_idx_1, int32_t reg16_idx_2, int32_t imm)
|
||||
{
|
||||
// generates: fn( ( reg1 + reg2 + imm ) & 0xFFFF )
|
||||
load_u16(&cs, reg16_idx_1);
|
||||
load_u16(&cs, reg16_idx_2);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, 0xFFFF);
|
||||
and_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void gen_modrm_entry_1(int32_t fn_idx, int32_t reg16_idx, int32_t imm)
|
||||
{
|
||||
// generates: fn ( ( reg + imm ) & 0xFFFF )
|
||||
load_u16(&cs, reg16_idx);
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
push_i32(&cs, 0xFFFF);
|
||||
and_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void jit_resolve_modrm16_(int32_t modrm_byte)
|
||||
{
|
||||
int32_t const ds = fn_get_seg_prefix_ds_idx;
|
||||
int32_t const ss = fn_get_seg_prefix_ss_idx;
|
||||
|
||||
switch(modrm_byte)
|
||||
{
|
||||
// The following casts cause some weird issue with emscripten and cause
|
||||
// a performance hit. XXX: look into this later.
|
||||
MODRM_ENTRY16_0(0, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_0(1, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + DI))
|
||||
MODRM_ENTRY16_0(2, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_0(3, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + DI))
|
||||
MODRM_ENTRY16_1(4, ds, (int32_t)(reg16 + SI))
|
||||
MODRM_ENTRY16_1(5, ds, (int32_t)(reg16 + DI))
|
||||
|
||||
// special case
|
||||
MODRM_ENTRY(0x00 | 6, call_fn_with_arg(&cs, ds, read_imm16()))
|
||||
MODRM_ENTRY(0x40 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm8s()))
|
||||
MODRM_ENTRY(0x80 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm16()))
|
||||
|
||||
MODRM_ENTRY16_1(7, ds, (int32_t)(reg16 + BX))
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_resolve_modrm16(int32_t modrm_byte)
|
||||
{
|
||||
push_u32(&cs, RESULT_LOC);
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
store_i32(&cs);
|
||||
}
|
||||
|
||||
#define MODRM_ENTRY32_0(row, seg, reg)\
|
||||
MODRM_ENTRY(0x00 | row, gen_modrm32_entry(seg, reg, 0))\
|
||||
MODRM_ENTRY(0x40 | row, gen_modrm32_entry(seg, reg, read_imm8s()))\
|
||||
MODRM_ENTRY(0x80 | row, gen_modrm32_entry(seg, reg, read_imm32s()))
|
||||
|
||||
static void gen_modrm32_entry(int32_t fn_idx, int32_t reg32s_idx, int32_t imm)
|
||||
{
|
||||
// generates: fn ( reg + imm )
|
||||
load_i32(&cs, reg32s_idx);
|
||||
push_i32(&cs, imm);
|
||||
add_i32(&cs);
|
||||
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
static void jit_resolve_sib(bool mod)
|
||||
{
|
||||
uint8_t sib_byte = read_imm8();
|
||||
uint8_t r = sib_byte & 7;
|
||||
uint8_t m = sib_byte >> 3 & 7;
|
||||
|
||||
int32_t base_addr;
|
||||
int32_t base;
|
||||
uint8_t seg;
|
||||
bool base_is_mem_access = true;
|
||||
|
||||
if(r == 4)
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + ESP);
|
||||
seg = SS;
|
||||
}
|
||||
else if(r == 5)
|
||||
{
|
||||
if(mod)
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + EBP);
|
||||
seg = SS;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = read_imm32s();
|
||||
seg = DS;
|
||||
base_is_mem_access = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base_addr = (int32_t)(reg32s + r);
|
||||
seg = DS;
|
||||
}
|
||||
|
||||
// generate: get_seg_prefix(seg) + base
|
||||
// Where base is accessed from memory if base_is_mem_access or written as a constant otherwise
|
||||
|
||||
dbg_assert(seg < 16);
|
||||
write_raw_u8(&cs, OP_I32CONST);
|
||||
write_raw_u8(&cs, seg);
|
||||
|
||||
call_fn(&cs, fn_get_seg_prefix_idx);
|
||||
|
||||
if(base_is_mem_access)
|
||||
{
|
||||
load_i32(&cs, base_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
push_i32(&cs, base);
|
||||
}
|
||||
|
||||
add_i32(&cs);
|
||||
|
||||
// We now have to generate an offset value to add
|
||||
|
||||
if(m == 4)
|
||||
{
|
||||
// offset is 0, we don't need to add anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Offset is reg32s[m] << s, where s is:
|
||||
|
||||
uint8_t s = sib_byte >> 6 & 3;
|
||||
|
||||
load_i32(&cs, (int32_t)(reg32s + m));
|
||||
// We don't use push_u32 here either since s will fit in 1 byte
|
||||
write_raw_u8(&cs, OP_I32CONST);
|
||||
write_raw_u8(&cs, s);
|
||||
shl_i32(&cs);
|
||||
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void modrm32_special_case_1()
|
||||
{
|
||||
jit_resolve_sib(true);
|
||||
push_i32(&cs, read_imm8s());
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void modrm32_special_case_2()
|
||||
{
|
||||
jit_resolve_sib(true);
|
||||
push_i32(&cs, read_imm32s());
|
||||
add_i32(&cs);
|
||||
}
|
||||
|
||||
static void jit_resolve_modrm32_(int32_t modrm_byte)
|
||||
{
|
||||
int32_t const ds = fn_get_seg_prefix_ds_idx;
|
||||
int32_t const ss = fn_get_seg_prefix_ss_idx;
|
||||
|
||||
switch(modrm_byte)
|
||||
{
|
||||
MODRM_ENTRY32_0(0, ds, (int32_t)(reg32s + EAX))
|
||||
MODRM_ENTRY32_0(1, ds, (int32_t)(reg32s + ECX))
|
||||
MODRM_ENTRY32_0(2, ds, (int32_t)(reg32s + EDX))
|
||||
MODRM_ENTRY32_0(3, ds, (int32_t)(reg32s + EBX))
|
||||
|
||||
// special cases
|
||||
MODRM_ENTRY(0x00 | 4, jit_resolve_sib(false))
|
||||
MODRM_ENTRY(0x40 | 4, modrm32_special_case_1())
|
||||
MODRM_ENTRY(0x80 | 4, modrm32_special_case_2())
|
||||
MODRM_ENTRY(0x00 | 5, call_fn_with_arg(&cs, ds, read_imm32s()))
|
||||
MODRM_ENTRY(0x40 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm8s()))
|
||||
MODRM_ENTRY(0x80 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm32s()))
|
||||
|
||||
MODRM_ENTRY32_0(6, ds, (int32_t)(reg32s + ESI))
|
||||
MODRM_ENTRY32_0(7, ds, (int32_t)(reg32s + EDI))
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_resolve_modrm32(int32_t modrm_byte)
|
||||
{
|
||||
push_i32(&cs, RESULT_LOC);
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
store_i32(&cs);
|
||||
}
|
||||
|
||||
#undef MODRM_ENTRY
|
||||
|
||||
void gen_modrm_fn1(char* fn, uint8_t fn_len, int32_t modrm_byte, int32_t arg0)
|
||||
{
|
||||
// generates: fn( modrm_resolve( modrm_byte ), arg0 )
|
||||
if(is_asize_32())
|
||||
{
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
}
|
||||
|
||||
push_i32(&cs, arg0);
|
||||
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_RET_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte)
|
||||
{
|
||||
// generates: fn( modrm_resolve( modrm_byte ) )
|
||||
if(is_asize_32())
|
||||
{
|
||||
jit_resolve_modrm32_(modrm_byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_resolve_modrm16_(modrm_byte);
|
||||
}
|
||||
|
||||
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_RET_TYPE_INDEX);
|
||||
call_fn(&cs, fn_idx);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
|
||||
#define FN0_TYPE_INDEX 0
|
||||
#define FN1_TYPE_INDEX 1
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include "util.h"
|
||||
|
||||
static Writer op;
|
||||
extern Writer cs;
|
||||
static Buffer op;
|
||||
static Buffer cs;
|
||||
|
||||
static void write_type_section()
|
||||
{
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
#define dbg_assert(condition) { if(DEBUG) { if(!(condition)) dbg_log(#condition); assert(condition); } }
|
||||
#define dbg_assert_message(condition, message) { if(DEBUG && !(condition)) { dbg_log(message); assert(false); } }
|
||||
|
||||
typedef struct Writer {
|
||||
typedef struct Buffer {
|
||||
uint8_t* const start;
|
||||
uint8_t* ptr;
|
||||
uint32_t const len;
|
||||
} Writer;
|
||||
} Buffer;
|
||||
|
||||
static void write_leb_i32(Writer* writer, int32_t v)
|
||||
static void write_leb_i32(Buffer* buf, int32_t v)
|
||||
{
|
||||
// Super complex stuff. See the following:
|
||||
// https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
|
||||
|
@ -40,11 +40,11 @@ static void write_leb_i32(Writer* writer, int32_t v)
|
|||
{
|
||||
byte |= 0b10000000; // turn on MSB
|
||||
}
|
||||
*(writer->ptr)++ = byte;
|
||||
*(buf->ptr)++ = byte;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_leb_u32(Writer* writer, uint32_t v)
|
||||
static void write_leb_u32(Buffer* buf, uint32_t v)
|
||||
{
|
||||
do {
|
||||
uint8_t byte = v & 0b1111111; // get last 7 bits
|
||||
|
@ -53,13 +53,13 @@ static void write_leb_u32(Writer* writer, uint32_t v)
|
|||
{
|
||||
byte |= 0b10000000; // turn on MSB
|
||||
}
|
||||
*(writer->ptr)++ = byte;
|
||||
*(buf->ptr)++ = byte;
|
||||
} while (v != 0);
|
||||
}
|
||||
|
||||
static void inline write_raw_u8(Writer* writer, uint8_t v)
|
||||
static void inline write_raw_u8(Buffer* buf, uint8_t v)
|
||||
{
|
||||
*(writer->ptr)++ = v;
|
||||
*(buf->ptr)++ = v;
|
||||
}
|
||||
|
||||
static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
|
||||
|
@ -69,14 +69,3 @@ static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
|
|||
*(ptr + 1) = x >> 7;
|
||||
}
|
||||
|
||||
/*123456789012345678901234567890123456789012345678901234567890123456789012345
|
||||
0 @@@@@@@@ @@@@@@@@@ @@ @ @@@@@@@@@ @@@@@@@ @ @ 0
|
||||
0 @ @ @ @ @ @ @ @ @ 0
|
||||
0 @ @ @ @ @ @ @ @ @ 0
|
||||
0 @@@@@@ @ @ @ @ @ @ @@@@@@@ 0
|
||||
0 @ @ @ @ @ @ @ @ @ 0
|
||||
0 @ @ @ @ @ @ @ @ @ 0
|
||||
0 @ @ @ @ @ @ @ @ @ 0
|
||||
0 @ @@@@@@@@@ @ @@ @@@@@@@@@ @@@@@@@ @ @ 0
|
||||
123456789012345678901234567890123456789012345678901234567890123456789012345*/
|
||||
|
||||
|
|
|
@ -5,67 +5,67 @@
|
|||
#include "wasm_opcodes.h"
|
||||
#include "util.h"
|
||||
|
||||
static void inline push_i32(Writer* w, int32_t v)
|
||||
static void inline push_i32(Buffer* buf, int32_t v)
|
||||
{
|
||||
write_raw_u8(w, OP_I32CONST);
|
||||
write_leb_i32(w, v);
|
||||
write_raw_u8(buf, OP_I32CONST);
|
||||
write_leb_i32(buf, v);
|
||||
}
|
||||
|
||||
static void inline push_u32(Writer* w, uint32_t v)
|
||||
static void inline push_u32(Buffer* buf, uint32_t v)
|
||||
{
|
||||
write_raw_u8(w, OP_I32CONST);
|
||||
write_leb_u32(w, v);
|
||||
write_raw_u8(buf, OP_I32CONST);
|
||||
write_leb_u32(buf, v);
|
||||
}
|
||||
|
||||
static void inline load_u16(Writer* w, uint32_t addr)
|
||||
static void inline load_u16(Buffer* buf, uint32_t addr)
|
||||
{
|
||||
write_raw_u8(w, OP_I32CONST);
|
||||
write_leb_u32(w, addr);
|
||||
write_raw_u8(w, OP_I32LOAD16U);
|
||||
write_raw_u8(w, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(w, MEM_IMM_OFFSET);
|
||||
write_raw_u8(buf, OP_I32CONST);
|
||||
write_leb_u32(buf, addr);
|
||||
write_raw_u8(buf, OP_I32LOAD16U);
|
||||
write_raw_u8(buf, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(buf, MEM_IMM_OFFSET);
|
||||
}
|
||||
|
||||
static void inline load_i32(Writer* w, uint32_t addr)
|
||||
static void inline load_i32(Buffer* buf, uint32_t addr)
|
||||
{
|
||||
write_raw_u8(w, OP_I32CONST);
|
||||
write_leb_u32(w, addr);
|
||||
write_raw_u8(w, OP_I32LOAD);
|
||||
write_raw_u8(w, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(w, MEM_IMM_OFFSET);
|
||||
write_raw_u8(buf, OP_I32CONST);
|
||||
write_leb_u32(buf, addr);
|
||||
write_raw_u8(buf, OP_I32LOAD);
|
||||
write_raw_u8(buf, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(buf, MEM_IMM_OFFSET);
|
||||
}
|
||||
|
||||
static void inline store_i32(Writer* w)
|
||||
static void inline store_i32(Buffer* buf)
|
||||
{
|
||||
write_raw_u8(w, OP_I32STORE);
|
||||
write_raw_u8(w, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(w, MEM_IMM_OFFSET);
|
||||
write_raw_u8(buf, OP_I32STORE);
|
||||
write_raw_u8(buf, MEM_IMM_ALIGNMENT);
|
||||
write_raw_u8(buf, MEM_IMM_OFFSET);
|
||||
}
|
||||
|
||||
static void inline add_i32(Writer* w)
|
||||
static void inline add_i32(Buffer* buf)
|
||||
{
|
||||
write_raw_u8(w, OP_I32ADD);
|
||||
write_raw_u8(buf, OP_I32ADD);
|
||||
}
|
||||
|
||||
static void inline and_i32(Writer* w)
|
||||
static void inline and_i32(Buffer* buf)
|
||||
{
|
||||
write_raw_u8(w, OP_I32AND);
|
||||
write_raw_u8(buf, OP_I32AND);
|
||||
}
|
||||
|
||||
static void inline shl_i32(Writer* w)
|
||||
static void inline shl_i32(Buffer* buf)
|
||||
{
|
||||
write_raw_u8(w, OP_I32SHL);
|
||||
write_raw_u8(buf, OP_I32SHL);
|
||||
}
|
||||
|
||||
static void inline call_fn(Writer* w, uint8_t fn_idx)
|
||||
static void inline call_fn(Buffer* buf, uint8_t fn_idx)
|
||||
{
|
||||
write_raw_u8(w, OP_CALL);
|
||||
write_raw_u8(w, fn_idx);
|
||||
write_raw_u8(buf, OP_CALL);
|
||||
write_raw_u8(buf, fn_idx);
|
||||
}
|
||||
|
||||
static void inline call_fn_with_arg(Writer* w, uint8_t fn_idx, int32_t arg0)
|
||||
static void inline call_fn_with_arg(Buffer* buf, uint8_t fn_idx, int32_t arg0)
|
||||
{
|
||||
push_i32(w, arg0);
|
||||
call_fn(w, fn_idx);
|
||||
push_i32(buf, arg0);
|
||||
call_fn(buf, fn_idx);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue