diff --git a/src/Makefile.am b/src/Makefile.am index ab44ff7..18da9e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,20 +70,20 @@ pcem_SOURCES += wx-sdl2-midi.c endif if CPU_I386 -pcem_SOURCES += codegen_backend_x86.c codegen_backend_x86_uops.c +pcem_SOURCES += codegen_backend_x86.c codegen_backend_x86_ops.c codegen_backend_x86_uops.c pcem_CFLAGS += -msse2 endif if CPU_X86_64 -pcem_SOURCES += codegen_backend_x86-64.c codegen_backend_x86-64_uops.c +pcem_SOURCES += codegen_backend_x86-64.c codegen_backend_x86-64_ops.c codegen_backend_x86-64_uops.c endif if CPU_ARM -pcem_SOURCES += codegen_backend_arm.c codegen_backend_arm_uops.c +pcem_SOURCES += codegen_backend_arm.c codegen_backend_arm_ops.c codegen_backend_arm_uops.c endif if CPU_ARM64 -pcem_SOURCES += codegen_backend_arm64.c codegen_backend_arm64_uops.c +pcem_SOURCES += codegen_backend_arm64.c codegen_backend_arm64_ops.c codegen_backend_arm64_uops.c endif if USE_NETWORKING diff --git a/src/codegen.c b/src/codegen.c index 96db8a6..5bd88bb 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -45,6 +45,41 @@ void codegen_generate_reset() has_ea = 0; } +void codegen_check_seg_read(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, &block->data[BLOCK_GPF_OFFSET]); + + seg->checked = 1; +} +void codegen_check_seg_write(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, &block->data[BLOCK_GPF_OFFSET]); + + seg->checked = 1; +} + static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { // pclog("codegen - mod=%i rm=%i reg=%i fetchdat=%08x\n", cpu_mod, cpu_rm, cpu_reg, fetchdat); @@ -203,6 +238,18 @@ static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uin return op_ea_seg; } +x86seg *codegen_generate_ea(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + if (op_32 & 0x200) + return codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + + return codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc); +} + static uint8_t opcode_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ diff --git a/src/codegen.h b/src/codegen.h index 8106c1c..9503b25 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -263,6 +263,10 @@ void codegen_generate_seg_restore(); void codegen_set_op32(); void codegen_flush(); void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr); +struct ir_data_t; +x86seg *codegen_generate_ea(struct ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32); +void codegen_check_seg_read(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); +void codegen_check_seg_write(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); extern int cpu_block_end; extern uint32_t codegen_endpc; diff --git a/src/codegen_backend_arm.c b/src/codegen_backend_arm.c index 41aeb71..09630ed 100644 --- a/src/codegen_backend_arm.c +++ b/src/codegen_backend_arm.c @@ -5,6 +5,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -15,6 +16,14 @@ #include #endif +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; + int codegen_host_reg_list[CODEGEN_HOST_REGS] = { REG_R4, @@ -22,6 +31,137 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_R6, }; +static void build_load_routine(codeblock_t *block, int size) +{ + uint32_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmemb386l + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + host_arm_MOV_REG_LSR(block, REG_R1, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R2, (uint32_t)readlookup2); + host_arm_LDR_REG_LSL(block, REG_R1, REG_R2, REG_R1, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R1, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1) + host_arm_LDRB_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 2) + host_arm_LDRH_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 4) + host_arm_LDR_REG(block, REG_R0, REG_R1, REG_R0); + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_SP, -4); + if (size == 1) + host_arm_BL(block, (uintptr_t)readmemb386l); + else if (size == 2) + host_arm_BL(block, (uintptr_t)readmemwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)readmemll); + else + fatal("build_load_routine - unknown size %i\n", size); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_SP, 4); + + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmemb386l + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + host_arm_MOV_REG_LSR(block, REG_R2, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R3, (uint32_t)writelookup2); + host_arm_LDR_REG_LSL(block, REG_R2, REG_R3, REG_R2, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R2, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1) + host_arm_STRB_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 2) + host_arm_STRH_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 4) + host_arm_STR_REG(block, REG_R1, REG_R2, REG_R0); + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_SP, -4); + if (size == 1) + host_arm_BL(block, (uintptr_t)writememb386l); + else if (size == 2) + host_arm_BL(block, (uintptr_t)writememwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)writememll); + else + fatal("build_store_routine - unknown size %i\n", size); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_SP, 4); + + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4); +} + void codegen_backend_init() { int c; @@ -57,6 +197,10 @@ void codegen_backend_init() } #endif // pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = BLOCK_SIZE; + block_pos = 0; + build_loadstore_routines(&codeblock[block_current]); } /*R11 - literal pool diff --git a/src/codegen_backend_arm64.c b/src/codegen_backend_arm64.c index e433f43..9df86f9 100644 --- a/src/codegen_backend_arm64.c +++ b/src/codegen_backend_arm64.c @@ -5,6 +5,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -15,6 +16,14 @@ #include #endif +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; + int codegen_host_reg_list[CODEGEN_HOST_REGS] = { REG_X19, @@ -24,6 +33,145 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_X23 }; +static void build_load_routine(codeblock_t *block, int size) +{ + uint32_t *branch_offset; + uint8_t *misaligned_offset; + int offset; + + /*In - W0 = address + Out - W0 = data, W1 = abrt*/ + /*MOV W1, W0, LSR #12 + MOV X2, #readlookup2 + LDR X1, [X2, X1, LSL #3] + CMP X1, #-1 + BEQ + + LDRB W0, [X1, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL readmemb386l + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + host_arm64_MOV_REG_LSR(block, REG_W1, REG_W0, 12); + offset = add_literal_q(block, (uintptr_t)readlookup2); + host_arm64_LDR_LITERAL_X(block, REG_X2, offset); + host_arm64_LDRX_REG_LSL3(block, REG_X1, REG_X2, REG_X1); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X1, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1) + host_arm64_LDRB_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 2) + host_arm64_LDRH_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 4) + host_arm64_LDR_REG(block, REG_W0, REG_W1, REG_W0); + host_arm64_MOVZ_IMM(block, REG_W1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block->data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block->data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_SP, -16); + if (size == 1) + host_arm64_call(block, (uintptr_t)readmemb386l); + else if (size == 2) + host_arm64_call(block, (uintptr_t)readmemwl); + else if (size == 4) + host_arm64_call(block, (uintptr_t)readmemll); + else + fatal("build_load_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_SP, 16); + host_arm64_RET(block, REG_X30); + + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + int offset; + + /*In - R0 = address, R1 = data + Out - R1 = abrt*/ + /*MOV W2, W0, LSR #12 + MOV X3, #writelookup2 + LDR X2, [X3, X2, LSL #3] + CMP X2, #-1 + BEQ + + STRB W1, [X2, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL writememb386l + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + host_arm64_MOV_REG_LSR(block, REG_W2, REG_W0, 12); + offset = add_literal_q(block, (uintptr_t)writelookup2); + host_arm64_LDR_LITERAL_X(block, REG_X3, offset); + host_arm64_LDRX_REG_LSL3(block, REG_X2, REG_X3, REG_X2); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X2, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1) + host_arm64_STRB_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 2) + host_arm64_STRH_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 4) + host_arm64_STR_REG(block, REG_X1, REG_X2, REG_X0); + host_arm64_MOVZ_IMM(block, REG_X1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block->data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block->data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_SP, -16); + if (size == 1) + host_arm64_call(block, (uintptr_t)writememb386l); + else if (size == 2) + host_arm64_call(block, (uintptr_t)writememwl); + else if (size == 4) + host_arm64_call(block, (uintptr_t)writememll); + else + fatal("build_store_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_SP, 16); + host_arm64_RET(block, REG_X30); + + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4); +} + void codegen_backend_init() { int c; @@ -59,6 +207,11 @@ void codegen_backend_init() } #endif // pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = BLOCK_SIZE; + block_pos = 0; + codegen_reset_literal_pool(&codeblock[block_current]); + build_loadstore_routines(&codeblock[block_current]); } /*R11 - literal pool diff --git a/src/codegen_backend_arm64_defs.h b/src/codegen_backend_arm64_defs.h index 7de61f0..48e58ec 100644 --- a/src/codegen_backend_arm64_defs.h +++ b/src/codegen_backend_arm64_defs.h @@ -75,4 +75,12 @@ #define REG_TEMP REG_X7 -#define CODEGEN_HOST_REGS 5 \ No newline at end of file +#define CODEGEN_HOST_REGS 5 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; \ No newline at end of file diff --git a/src/codegen_backend_arm64_ops.c b/src/codegen_backend_arm64_ops.c new file mode 100644 index 0000000..4effa1a --- /dev/null +++ b/src/codegen_backend_arm64_ops.c @@ -0,0 +1,613 @@ +#ifdef __aarch64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" + + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + *(uint32_t *)&block->data[block_pos] = val; + block_pos += 4; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +#define Rt(x) (x) +#define Rd(x) (x) +#define Rn(x) ((x) << 5) +#define Rt2(x) ((x) << 10) +#define Rm(x) ((x) << 16) + +#define shift_imm6(x) ((x) << 10) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define COND_EQ (0x0) +#define COND_NE (0x1) + +#define OPCODE_SHIFT 24 +#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) +#define OPCODE_BCOND (0x54 << OPCODE_SHIFT) +#define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_CMNX_IMM (0xb1 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x71 << OPCODE_SHIFT) +#define OPCODE_CMPX_IMM (0xf1 << OPCODE_SHIFT) +#define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT) +#define OPCODE_LDR_LITERAL_X (0x58 << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x51 << OPCODE_SHIFT) + +#define OPCODE_AND_IMM (0x024 << 23) +#define OPCODE_ANDS_IMM (0x0e4 << 23) +#define OPCODE_EOR_IMM (0x0a4 << 23) +#define OPCODE_MOVK_W (0x0e5 << 23) +#define OPCODE_MOVZ_W (0x0a5 << 23) +#define OPCODE_ORR_IMM (0x064 << 23) + +#define OPCODE_BFI (0x0cc << 22) +#define OPCODE_LDR_IMM_W (0x2e5 << 22) +#define OPCODE_LDRB_IMM_W (0x0e5 << 22) +#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) +#define OPCODE_STP_PREIDX_X (0x2a6 << 22) +#define OPCODE_STR_IMM_W (0x2e4 << 22) +#define OPCODE_STR_IMM_Q (0x3e4 << 22) +#define OPCODE_STRB_IMM (0x0e4 << 22) +#define OPCODE_UBFX (0x14c << 22) + +#define OPCODE_ADD_LSL (0x058 << 21) +#define OPCODE_ADD_LSR (0x05a << 21) +#define OPCODE_AND_ASR (0x054 << 21) +#define OPCODE_AND_LSL (0x050 << 21) +#define OPCODE_AND_ROR (0x056 << 21) +#define OPCODE_ANDS_LSL (0x350 << 21) +#define OPCODE_EOR_LSL (0x250 << 21) +#define OPCODE_ORR_LSL (0x150 << 21) +#define OPCODE_ORR_LSR (0x152 << 21) +#define OPCODE_SUB_LSL (0x258 << 21) +#define OPCODE_SUB_LSR (0x25a << 21) + +#define OPCODE_BLR (0xd63f0000) +#define OPCODE_LDR_REG (0xb8606800) +#define OPCODE_LDRB_REG (0x38606800) +#define OPCODE_LDRH_REG (0x78606800) +#define OPCODE_LDRX_REG_LSL3 (0xf8607800) +#define OPCODE_NOP (0xd503201f) +#define OPCODE_RET (0xd65f0000) +#define OPCODE_STR_REG (0xb8206800) +#define OPCODE_STRB_REG (0x38206800) +#define OPCODE_STRH_REG (0x78206800) + +#define DATPROC_SHIFT(sh) (sh << 10) +#define DATPROC_IMM_SHIFT(sh) (sh << 22) +#define MOV_WIDE_HW(hw) (hw << 21) + +#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) +#define IMM12(imm_data) ((imm_data) << 10) +#define IMM16(imm_data) ((imm_data) << 5) + +#define IMMN(immn) ((immn) << 22) +#define IMMR(immr) ((immr) << 16) +#define IMMS(imms) ((imms) << 10) + +#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) + +#define OFFSET12_B(offset) (offset << 10) +#define OFFSET12_W(offset) ((offset >> 2) << 10) +#define OFFSET12_Q(offset) ((offset >> 3) << 10) + +static int literal_offset = 0; +void codegen_reset_literal_pool(codeblock_t *block) +{ + literal_offset = 0; +} + +/*Returns true if offset fits into 19 bits*/ +static int offset_is_19bit(int offset) +{ + if (offset >= (1 << (18+2))) + return 0; + if (offset < -(1 << (18+2))) + return 0; + return 1; +} + +int add_literal(codeblock_t *block, uint32_t data) +{ + if (literal_offset >= 4096) + fatal("add_literal - literal pool full\n"); + + *(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; + + literal_offset += 4; + + return literal_offset - 4; +} + +int add_literal_q(codeblock_t *block, uint64_t data) +{ + if (literal_offset & 4) + literal_offset += 4; + + if (literal_offset >= 4096-4) + fatal("add_literal - literal pool full\n"); + + *(uint64_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; + + literal_offset += 8; + + return literal_offset - 8; +} + +static inline int imm_is_imm16(uint32_t imm_data) +{ + if (!(imm_data & 0xffff0000) || !(imm_data & 0x0000ffff)) + return 1; + return 0; +} +static inline int imm_is_imm12(uint32_t imm_data) +{ + if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) + return 1; + return 0; +} + +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_SUB_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (imm_data == 0xff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x07)); + } + else if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); + } + else if (imm_data == 0xffffff00) + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x17)); + } + else if (imm_data == 0xffff00ff) + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x17)); + } + else if (imm_data == 0x0000ff00) + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x07)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (imm_data == 0xff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x07)); + } + else if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); + } + else if (imm_data == 0xffffff00) + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x17)); + } + else if (imm_data == 0xffff00ff) + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x17)); + } + else if (imm_data == 0x0000ff00) + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x07)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ANDS_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR((32 - lsb) & 31) | IMMS((width-1) & 31)); +} + +void host_arm64_BLR(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLR | Rn(addr_reg)); +} + +uint32_t *host_arm64_BEQ_(codeblock_t *block) +{ + codegen_addlong(block, OPCODE_BCOND | COND_EQ); + return &block->data[block_pos-4]; +} +uint32_t *host_arm64_BNE_(codeblock_t *block) +{ + codegen_addlong(block, OPCODE_BCOND | COND_NE); + return &block->data[block_pos-4]; +} + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest) +{ + int offset = (uintptr_t)dest - (uintptr_t)opcode; + *opcode |= OFFSET19(offset); +} + +void host_arm64_BEQ(codeblock_t *block, void *dest) +{ + uint32_t *opcode = host_arm64_BEQ_(block); + host_arm64_branch_set_offset(opcode, dest); +} + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest) +{ + int offset = dest - (uintptr_t)&block->data[block_pos]; + if (!offset_is_19bit(offset)) + fatal("host_arm64_CBNZ - offset out of range %x\n", offset); + codegen_addlong(block, OPCODE_CBNZ | OFFSET19(offset) | Rt(reg)); +} + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMP_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMN_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMN_IMM %08x\n", imm_data); +} +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMPX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMNX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMNX_IMM %08x\n", imm_data); +} + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMN_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMP_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMP_IMM %08x\n", imm_data); +} +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMNX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMPX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMPX_IMM %08x\n", imm_data); +} + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_LDP_POSTIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} + +void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset) +{ + int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos; + + if (!offset_is_19bit(offset)) + fatal("host_arm64_CBNZ - offset out of range %x\n", offset); + + codegen_addlong(block, OPCODE_LDR_LITERAL_W | OFFSET19(offset) | Rt(dest_reg)); +} +void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset) +{ + int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos; + + if (!offset_is_19bit(offset)) + fatal("host_arm64_CBNZ - offset out of range %x\n", offset); + + codegen_addlong(block, OPCODE_LDR_LITERAL_X | OFFSET19(offset) | Rt(dest_reg)); +} +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_LDRB_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDRB_IMM_W | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRX_REG_LSL3 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + if (dst_reg != src_m_reg) + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVZ_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVZ_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVK_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVK_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_NOP(codeblock_t *block) +{ + codegen_addlong(block, OPCODE_NOP); +} + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); + } + else if (imm_data == 0xffff0000) + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x0f)); + } + else if (imm_data == 0xffffff00) + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x17)); + } + else if (imm_data == 0xffff00ff) + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x17)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_RET(codeblock_t *block, int reg) +{ + codegen_addlong(block, OPCODE_RET | Rn(reg)); +} + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_STP_PREIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_STP_PREIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_Q | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_STRB_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STRB_IMM | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_ADD_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_UBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); +} + + +void host_arm64_call(codeblock_t *block, void *dst_addr) +{ + int offset = add_literal_q(block, (uintptr_t)dst_addr); + host_arm64_LDR_LITERAL_X(block, REG_X16, offset); + host_arm64_BLR(block, REG_X16); +} + +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (imm_is_imm16(imm_data)) + host_arm64_MOVZ_IMM(block, reg, imm_data); + else + { + host_arm64_MOVZ_IMM(block, reg, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, reg, imm_data & 0xffff0000); + } +} + +#endif \ No newline at end of file diff --git a/src/codegen_backend_arm64_ops.h b/src/codegen_backend_arm64_ops.h new file mode 100644 index 0000000..6178c6b --- /dev/null +++ b/src/codegen_backend_arm64_ops.h @@ -0,0 +1,92 @@ +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_BLR(codeblock_t *block, int addr_reg); + +void host_arm64_BEQ(codeblock_t *block, void *dest); + +uint32_t *host_arm64_BEQ_(codeblock_t *block); +uint32_t *host_arm64_BNE_(codeblock_t *block); + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest); + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest); + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_arm64_NOP(codeblock_t *block); + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_RET(codeblock_t *block, int reg); + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); + +#define host_arm64_TST_IMM(block, src_n_reg, imm_data) host_arm64_ANDS_IMM(block, REG_XZR, src_n_reg, imm_data) + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_call(codeblock_t *block, void *dst_addr); +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); + + +#define in_range7_x(offset) (((offset) >= -0x200) && ((offset) < (0x200)) && !((offset) & 7)) +#define in_range12_b(offset) (((offset) >= 0) && ((offset) < 0x1000)) +#define in_range12_w(offset) (((offset) >= 0) && ((offset) < 0x4000) && !((offset) & 3)) +#define in_range12_q(offset) (((offset) >= 0) && ((offset) < 0x8000) && !((offset) & 7)) + + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); + +int add_literal_q(codeblock_t *block, uint64_t data); \ No newline at end of file diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c index b641a4b..8b5aad0 100644 --- a/src/codegen_backend_arm64_uops.c +++ b/src/codegen_backend_arm64_uops.c @@ -4,459 +4,9 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" #include "codegen_ir_defs.h" -static inline void codegen_addlong(codeblock_t *block, uint32_t val) -{ - *(uint32_t *)&block->data[block_pos] = val; - block_pos += 4; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addlong over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -#define Rt(x) (x) -#define Rd(x) (x) -#define Rn(x) ((x) << 5) -#define Rt2(x) ((x) << 10) -#define Rm(x) ((x) << 16) - -#define shift_imm6(x) ((x) << 10) - -#define DATA_OFFSET_UP (1 << 23) -#define DATA_OFFSET_DOWN (0 << 23) - -#define COND_SHIFT 28 -#define COND_NE (0x1 << COND_SHIFT) -#define COND_AL (0xe << COND_SHIFT) - -#define OPCODE_SHIFT 24 -#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) -#define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) -#define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT) -#define OPCODE_LDR_LITERAL_X (0x58 << OPCODE_SHIFT) -#define OPCODE_SUB_IMM (0x51 << OPCODE_SHIFT) - -#define OPCODE_AND_IMM (0x024 << 23) -#define OPCODE_EOR_IMM (0x0a4 << 23) -#define OPCODE_MOVK_W (0x0e5 << 23) -#define OPCODE_MOVZ_W (0x0a5 << 23) -#define OPCODE_ORR_IMM (0x064 << 23) - -#define OPCODE_BFI (0x0cc << 22) -#define OPCODE_LDR_IMM_W (0x2e5 << 22) -#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) -#define OPCODE_STP_PREIDX_X (0x2a6 << 22) -#define OPCODE_STR_IMM_W (0x2e4 << 22) -#define OPCODE_STR_IMM_Q (0x3e4 << 22) -#define OPCODE_STRB_IMM (0x0e4 << 22) -#define OPCODE_UBFX (0x14c << 22) - -#define OPCODE_ADD_LSL (0x058 << 21) -#define OPCODE_ADD_LSR (0x05a << 21) -#define OPCODE_AND_ASR (0x054 << 21) -#define OPCODE_AND_LSL (0x050 << 21) -#define OPCODE_AND_ROR (0x056 << 21) -#define OPCODE_EOR_LSL (0x250 << 21) -#define OPCODE_ORR_LSL (0x150 << 21) -#define OPCODE_ORR_LSR (0x152 << 21) -#define OPCODE_SUB_LSL (0x258 << 21) -#define OPCODE_SUB_LSR (0x25a << 21) - -#define OPCODE_BLR (0xd63f0000) -#define OPCODE_NOP (0xd503201f) -#define OPCODE_RET (0xd65f0000) - -#define DATPROC_SHIFT(sh) (sh << 10) -#define DATPROC_IMM_SHIFT(sh) (sh << 22) -#define MOV_WIDE_HW(hw) (hw << 21) - -#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) -#define IMM12(imm_data) ((imm_data) << 10) -#define IMM16(imm_data) ((imm_data) << 5) - -#define IMMN(immn) ((immn) << 22) -#define IMMR(immr) ((immr) << 16) -#define IMMS(imms) ((imms) << 10) - -#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) - -#define OFFSET12_B(offset) (offset << 10) -#define OFFSET12_W(offset) ((offset >> 2) << 10) -#define OFFSET12_Q(offset) ((offset >> 3) << 10) - -static int literal_offset = 0; -void codegen_reset_literal_pool(codeblock_t *block) -{ - literal_offset = 0; -} - -/*Returns true if offset fits into 19 bits*/ -static int offset_is_19bit(int offset) -{ - if (offset >= (1 << (18+2))) - return 0; - if (offset < -(1 << (18+2))) - return 0; - return 1; -} - -#define in_range7_x(offset) (((offset) >= -0x200) && ((offset) < (0x200)) && !((offset) & 7)) -#define in_range12_b(offset) (((offset) >= 0) && ((offset) < 0x1000)) -#define in_range12_w(offset) (((offset) >= 0) && ((offset) < 0x4000) && !((offset) & 3)) -#define in_range12_q(offset) (((offset) >= 0) && ((offset) < 0x8000) && !((offset) & 7)) - -int add_literal(codeblock_t *block, uint32_t data) -{ - if (literal_offset >= 4096) - fatal("add_literal - literal pool full\n"); - - *(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; - - literal_offset += 4; - - return literal_offset - 4; -} - -int add_literal_q(codeblock_t *block, uint64_t data) -{ - if (literal_offset & 4) - literal_offset += 4; - - if (literal_offset >= 4096-4) - fatal("add_literal - literal pool full\n"); - - *(uint64_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; - - literal_offset += 8; - - return literal_offset - 8; -} - -static inline int imm_is_imm16(uint32_t imm_data) -{ - if (!(imm_data & 0xffff0000) || !(imm_data & 0x0000ffff)) - return 1; - return 0; -} -static inline int imm_is_imm12(uint32_t imm_data) -{ - if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) - return 1; - return 0; -} - -void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); -void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); - -void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) -{ - if (!imm_data) - host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); - else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) - { - host_arm64_SUB_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); - } - else if (!(imm_data & 0xff000000)) - { - if (imm_data & 0xfff) - { - codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); - if (imm_data & 0xfff000) - codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); - } - else if (imm_data & 0xfff000) - codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); - } - else - { - host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); - host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); - codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); - } -} -void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} -void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_ADD_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} -//12001c00 S=0 R=7 -void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) -{ - if (imm_data == 0xff) /*Quick hack until proper immediate generation is written */ - { - codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x07)); - } - else if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ - { - codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); - } - else if (imm_data == 0xffffff00) - { - codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x17)); - } - else if (imm_data == 0xffff00ff) - { - codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x17)); - } - else if (imm_data == 0x0000ff00) - { - codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x07)); - } - else - { - host_arm64_mov_imm(block, REG_W16, imm_data); - codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); - } -} -void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} -void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_AND_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} -void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_AND_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) -{ - codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR((32 - lsb) & 31) | IMMS((width-1) & 31)); -} - -void host_arm64_BLR(codeblock_t *block, int addr_reg) -{ - codegen_addlong(block, OPCODE_BLR | Rn(addr_reg)); -} - -void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest) -{ - int offset = dest - (uintptr_t)&block->data[block_pos]; - if (!offset_is_19bit(offset)) - fatal("host_arm64_CBNZ - offset out of range %x\n", offset); - codegen_addlong(block, OPCODE_CBNZ | OFFSET19(offset) | Rt(reg)); -} - -void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) -{ - if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ - { - codegen_addlong(block, OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); - } - else - { - host_arm64_mov_imm(block, REG_W16, imm_data); - codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); - } -} -void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) -{ - if (!in_range7_x(offset)) - fatal("host_arm64_LDP_POSTIDX out of range7 %i\n", offset); - codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); -} - -void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) -{ - if (!in_range12_w(offset)) - fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset); - codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); -} - -void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset) -{ - int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos; - - if (!offset_is_19bit(offset)) - fatal("host_arm64_CBNZ - offset out of range %x\n", offset); - - codegen_addlong(block, OPCODE_LDR_LITERAL_W | OFFSET19(offset) | Rt(dest_reg)); -} -void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset) -{ - int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos; - - if (!offset_is_19bit(offset)) - fatal("host_arm64_CBNZ - offset out of range %x\n", offset); - - codegen_addlong(block, OPCODE_LDR_LITERAL_X | OFFSET19(offset) | Rt(dest_reg)); -} - -void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) -{ - if (dst_reg != src_m_reg) - codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_ORR_LSR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data) -{ - int hw; - - if (!imm_is_imm16(imm_data)) - fatal("MOVZ_IMM - imm not representable %08x\n", imm_data); - - hw = (imm_data & 0xffff0000) ? 1 : 0; - if (hw) - imm_data >>= 16; - - codegen_addlong(block, OPCODE_MOVZ_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); -} - -void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data) -{ - int hw; - - if (!imm_is_imm16(imm_data)) - fatal("MOVK_IMM - imm not representable %08x\n", imm_data); - - hw = (imm_data & 0xffff0000) ? 1 : 0; - if (hw) - imm_data >>= 16; - - codegen_addlong(block, OPCODE_MOVK_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); -} - -void host_arm64_NOP(codeblock_t *block) -{ - codegen_addlong(block, OPCODE_NOP); -} - -void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) -{ - if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ - { - codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(0) | IMMS(0x0f)); - } - else if (imm_data == 0xffff0000) - { - codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x0f)); - } - else if (imm_data == 0xffffff00) - { - codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(24) | IMMS(0x17)); - } - else if (imm_data == 0xffff00ff) - { - codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMMN(0) | IMMR(16) | IMMS(0x17)); - } - else - { - host_arm64_mov_imm(block, REG_W16, imm_data); - codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); - } -} -void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_RET(codeblock_t *block, int reg) -{ - codegen_addlong(block, OPCODE_RET | Rn(reg)); -} - -void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) -{ - if (!in_range7_x(offset)) - fatal("host_arm64_STP_PREIDX out of range7 %i\n", offset); - codegen_addlong(block, OPCODE_STP_PREIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); -} - -void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) -{ - if (!in_range12_w(offset)) - fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); - codegen_addlong(block, OPCODE_STR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); -} -void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset) -{ - if (!in_range12_q(offset)) - fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); - codegen_addlong(block, OPCODE_STR_IMM_Q | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); -} -void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) -{ - if (!in_range12_b(offset)) - fatal("host_arm64_STRB_IMM out of range12 %i\n", offset); - codegen_addlong(block, OPCODE_STRB_IMM | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); -} - -void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) -{ - if (!imm_data) - host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); - else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) - { - host_arm64_ADD_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); - } - else if (!(imm_data & 0xff000000)) - { - if (imm_data & 0xfff) - { - codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); - if (imm_data & 0xfff000) - codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); - } - else if (imm_data & 0xfff000) - codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); - } - else - { - host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); - host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); - codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); - } -} -void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} -void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) -{ - codegen_addlong(block, OPCODE_SUB_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); -} - -void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) -{ - codegen_addlong(block, OPCODE_UBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); -} - -void host_arm64_call(codeblock_t *block, void *dst_addr) -{ - int offset = add_literal_q(block, (uintptr_t)dst_addr); - host_arm64_LDR_LITERAL_X(block, REG_X16, offset); - host_arm64_BLR(block, REG_X16); -} - -void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data) -{ - if (imm_is_imm16(imm_data)) - host_arm64_MOVZ_IMM(block, reg, imm_data); - else - { - host_arm64_MOVZ_IMM(block, reg, imm_data & 0xffff); - host_arm64_MOVK_IMM(block, reg, imm_data & 0xffff0000); - } -} - #define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0x1f) #define REG_IS_L(size) (size == IREG_SIZE_L) @@ -605,7 +155,7 @@ static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) } else fatal("AND_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); - + return 0; } @@ -617,6 +167,22 @@ static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm64_BEQ(block, uop->p); + + return 0; +} + static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) { host_arm64_mov_imm(block, REG_ARG0, uop->imm_data); @@ -642,6 +208,186 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_IMM(block, REG_X0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm64_ADD_IMM(block, REG_W0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_byte); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_word); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_long); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + static int codegen_MOV(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); @@ -799,7 +545,7 @@ static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) } else fatal("OR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); - + return 0; } @@ -978,7 +724,7 @@ static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) } else fatal("XOR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); - + return 0; } @@ -994,6 +740,15 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, @@ -1009,9 +764,19 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_SUB & UOP_MASK] = codegen_SUB, [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, [UOP_XOR & UOP_MASK] = codegen_XOR, - [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ }; +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDRB_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_8 - not in range\n"); +} + void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) { if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) diff --git a/src/codegen_backend_arm_defs.h b/src/codegen_backend_arm_defs.h index 1fadfa1..3ec520b 100644 --- a/src/codegen_backend_arm_defs.h +++ b/src/codegen_backend_arm_defs.h @@ -45,4 +45,12 @@ #define REG_MASK_LOCAL (REG_MASK_R4 | REG_MASK_R5 | REG_MASK_R6 | REG_MASK_R7 | \ REG_MASK_R8 | REG_MASK_R9 | REG_MASK_R10 | REG_MASK_R11) -#define CODEGEN_HOST_REGS 3 \ No newline at end of file +#define CODEGEN_HOST_REGS 3 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; diff --git a/src/codegen_backend_arm_ops.c b/src/codegen_backend_arm_ops.c new file mode 100644 index 0000000..f7772ae --- /dev/null +++ b/src/codegen_backend_arm_ops.c @@ -0,0 +1,587 @@ +#ifdef __ARM_EABI__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + *(uint32_t *)&block->data[block_pos] = val; + block_pos += 4; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +#define Rm(x) (x) +#define Rd(x) ((x) << 12) +#define Rn(x) ((x) << 16) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define COND_SHIFT 28 +#define COND_EQ (0x0 << COND_SHIFT) +#define COND_NE (0x1 << COND_SHIFT) +#define COND_AL (0xe << COND_SHIFT) + +#define OPCODE_SHIFT 20 +#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) +#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT) +#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT) +#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT) +#define OPCODE_B (0xa0 << OPCODE_SHIFT) +#define OPCODE_BIC_IMM (0x3c << OPCODE_SHIFT) +#define OPCODE_BIC_REG (0x1c << OPCODE_SHIFT) +#define OPCODE_BL (0xb0 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x37 << OPCODE_SHIFT) +#define OPCODE_CMN_REG (0x17 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x35 << OPCODE_SHIFT) +#define OPCODE_CMP_REG (0x15 << OPCODE_SHIFT) +#define OPCODE_EOR_IMM (0x22 << OPCODE_SHIFT) +#define OPCODE_EOR_REG (0x02 << OPCODE_SHIFT) +#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) +#define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT) +#define OPCODE_LDR_IMM_POST (0x41 << OPCODE_SHIFT) +#define OPCODE_LDR_REG (0x79 << OPCODE_SHIFT) +#define OPCODE_LDRB_IMM (0x55 << OPCODE_SHIFT) +#define OPCODE_LDRB_REG (0x7d << OPCODE_SHIFT) +#define OPCODE_MOV_IMM (0x3a << OPCODE_SHIFT) +#define OPCODE_MOVT_IMM (0x34 << OPCODE_SHIFT) +#define OPCODE_MOVW_IMM (0x30 << OPCODE_SHIFT) +#define OPCODE_MOV_REG (0x1a << OPCODE_SHIFT) +#define OPCODE_MVN_REG (0x1e << OPCODE_SHIFT) +#define OPCODE_ORR_IMM (0x38 << OPCODE_SHIFT) +#define OPCODE_ORR_REG (0x18 << OPCODE_SHIFT) +#define OPCODE_RSB_REG (0x06 << OPCODE_SHIFT) +#define OPCODE_STMDB_WB (0x92 << OPCODE_SHIFT) +#define OPCODE_STR_IMM (0x50 << OPCODE_SHIFT) +#define OPCODE_STR_IMM_WB (0x52 << OPCODE_SHIFT) +#define OPCODE_STR_REG (0x78 << OPCODE_SHIFT) +#define OPCODE_STRB_IMM (0x54 << OPCODE_SHIFT) +#define OPCODE_STRB_REG (0x7c << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x24 << OPCODE_SHIFT) +#define OPCODE_SUB_REG (0x04 << OPCODE_SHIFT) +#define OPCODE_TST_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_TST_REG (0x11 << OPCODE_SHIFT) + +#define OPCODE_BFI 0xe7c00010 +#define OPCODE_BLX 0xe12fff30 +#define OPCODE_LDRH_REG 0xe19000b0 +#define OPCODE_STRH_REG 0xe18000b0 +#define OPCODE_UADD8 0xe6500f90 +#define OPCODE_UADD16 0xe6500f10 +#define OPCODE_USUB8 0xe6500ff0 +#define OPCODE_USUB16 0xe6500f70 +#define OPCODE_UXTB 0xe6ef0070 +#define OPCODE_UXTH 0xe6ff0070 + +#define B_OFFSET(x) (((x) >> 2) & 0xffffff) + +#define SHIFT_TYPE_SHIFT 5 +#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT) + +#define SHIFT_TYPE_IMM (0 << 4) +#define SHIFT_TYPE_REG (1 << 4) + +#define SHIFT_IMM_SHIFT 7 +#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_LSR_IMM(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) + +#define BFI_lsb(lsb) ((lsb) << 7) +#define BFI_msb(msb) ((msb) << 16) + +#define UXTB_ROTATE(rotate) (((rotate) >> 3) << 10) + +#define MOVT_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) +#define MOVW_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) + +static int literal_offset = 0; +void codegen_reset_literal_pool(codeblock_t *block) +{ + literal_offset = 0; +} + +int add_literal(codeblock_t *block, uint32_t data) +{ + int c; + + if (literal_offset >= 4096) + fatal("add_literal - literal pool full\n"); + + /*Search for pre-existing value*/ + for (c = 0; c < literal_offset; c += 4) + { + if (*(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + c] == data) + return c; + } + + *(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; + + literal_offset += 4; + + return literal_offset - 4; +} + + +static inline uint32_t arm_data_offset(int offset) +{ + if (offset < -0xffc || offset > 0xffc) + fatal("arm_data_offset out of range - %i\n", offset); + + if (offset >= 0) + return offset | DATA_OFFSET_UP; + return (-offset) | DATA_OFFSET_DOWN; +} + +static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) +{ + int shift = 0; +//pclog("get_arm_imm - imm_data=%08x\n", imm_data); + if (!(imm_data & 0xffff)) + { + shift += 16; + imm_data >>= 16; + } + if (!(imm_data & 0xff)) + { + shift += 8; + imm_data >>= 8; + } + if (!(imm_data & 0xf)) + { + shift += 4; + imm_data >>= 4; + } + if (!(imm_data & 0x3)) + { + shift += 2; + imm_data >>= 2; + } + if (imm_data > 0xff) /*Note - should handle rotation round the word*/ + return 0; +//pclog(" imm_data=%02x shift=%i\n", imm_data, shift); + *arm_imm = imm_data | ((((32 - shift) >> 1) & 15) << 8); + return 1; +} + +static inline int in_range(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < -4095 || diff > 4095) + return 0; + return 1; +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_SUB_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else if (get_arm_imm(~imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rm(src_reg) | BFI_lsb(lsb) | BFI_msb((lsb + width) - 1)); +} + +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset = (dest_addr - (uintptr_t)&block->data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R3, dest_addr); + host_arm_BLX(block, REG_R3); + } + else + codegen_addlong(block, COND_AL | OPCODE_BL | B_OFFSET(offset)); +} +void host_arm_BLX(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); +} + +uint32_t *host_arm_BEQ_(codeblock_t *block) +{ + codegen_addlong(block, COND_EQ | OPCODE_B); + + return (uint32_t *)&block->data[block_pos - 4]; +} +uint32_t *host_arm_BNE_(codeblock_t *block) +{ + codegen_addlong(block, COND_NE | OPCODE_B); + + return (uint32_t *)&block->data[block_pos - 4]; +} + +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset = (dest_addr - (uintptr_t)&block->data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BEQ - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_EQ | OPCODE_B | B_OFFSET(offset)); +} +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset = (dest_addr - (uintptr_t)&block->data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BNE - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_NE | OPCODE_B | B_OFFSET(offset)); +} + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMP_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMN_IMM | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_CMN_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMN_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMN_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMP_IMM | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_CMP_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMP_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_EOR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_EOR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_LDMIA_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM_POST | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRB_ABS(codeblock_t *block, int dst_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDRB_IMM(block, dst_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("LDRB_ABS - not in range\n"); +} +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRH_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg)); +} + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); + } + else + { + host_arm_MOVW_IMM(block, dst_reg, imm & 0xffff); + if (imm >> 16) + host_arm_MOVT_IMM(block, dst_reg, imm >> 16); + } +} + +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVT_IMM | Rd(dst_reg) | MOVT_IMM(imm)); +} +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVW_IMM | Rd(dst_reg) | MOVW_IMM(imm)); +} + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MVN_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_ORR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_ORR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ORR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_STMDB_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM_WB | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_STRH_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg)); +} + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_ADD_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_SUB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_TST_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_TST_IMM | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_TST_REG(block, src_reg, REG_TEMP); + } +} +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2) +{ + codegen_addlong(block, COND_AL | OPCODE_TST_REG | Rn(src_reg1) | Rm(src_reg2)); +} + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +#endif \ No newline at end of file diff --git a/src/codegen_backend_arm_ops.h b/src/codegen_backend_arm_ops.h new file mode 100644 index 0000000..31aee46 --- /dev/null +++ b/src/codegen_backend_arm_ops.h @@ -0,0 +1,84 @@ +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +#define host_arm_ADD_REG(block, dst_reg, src_reg_n, src_reg_m) host_arm_ADD_REG_LSL(block, dst_reg, src_reg_n, src_reg_m, 0) +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BLX(codeblock_t *block, int addr_reg); +uint32_t *host_arm_BEQ_(codeblock_t *block); +uint32_t *host_arm_BNE_(codeblock_t *block); +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr); + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm); +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm); +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDR_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDR_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRB_ABS(codeblock_t *block, int dst, void *p); +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDRB_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDRB_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg); + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm); +#define host_arm_MOV_REG(block, dst_reg, src_reg) host_arm_MOV_REG_LSL(block, dst_reg, src_reg, 0) +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm); +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm); + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm_ORR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STR_REG(block, src_reg, addr_reg, offset_reg) host_arm_STR_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STRB_REG(block, src_reg, addr_reg, offset_reg) host_arm_STRB_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg); + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_TST_IMM(codeblock_t *block, int src_reg1, uint32_t imm); +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2); + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c index 17fd823..b6f5f41 100644 --- a/src/codegen_backend_arm_uops.c +++ b/src/codegen_backend_arm_uops.c @@ -4,125 +4,9 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" #include "codegen_ir_defs.h" -static inline void codegen_addlong(codeblock_t *block, uint32_t val) -{ - *(uint32_t *)&block->data[block_pos] = val; - block_pos += 4; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addlong over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -#define Rm(x) (x) -#define Rd(x) ((x) << 12) -#define Rn(x) ((x) << 16) - -#define DATA_OFFSET_UP (1 << 23) -#define DATA_OFFSET_DOWN (0 << 23) - -#define COND_SHIFT 28 -#define COND_NE (0x1 << COND_SHIFT) -#define COND_AL (0xe << COND_SHIFT) - -#define OPCODE_SHIFT 20 -#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) -#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT) -#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT) -#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT) -#define OPCODE_B (0xa0 << OPCODE_SHIFT) -#define OPCODE_BIC_IMM (0x3c << OPCODE_SHIFT) -#define OPCODE_BIC_REG (0x1c << OPCODE_SHIFT) -#define OPCODE_EOR_IMM (0x22 << OPCODE_SHIFT) -#define OPCODE_EOR_REG (0x02 << OPCODE_SHIFT) -#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) -#define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT) -#define OPCODE_MOV_IMM (0x3a << OPCODE_SHIFT) -#define OPCODE_MOVW_IMM (0x30 << OPCODE_SHIFT) -#define OPCODE_MOV_REG (0x1a << OPCODE_SHIFT) -#define OPCODE_MVN_REG (0x1e << OPCODE_SHIFT) -#define OPCODE_ORR_IMM (0x38 << OPCODE_SHIFT) -#define OPCODE_ORR_REG (0x18 << OPCODE_SHIFT) -#define OPCODE_RSB_REG (0x06 << OPCODE_SHIFT) -#define OPCODE_STMDB_WB (0x92 << OPCODE_SHIFT) -#define OPCODE_STR_IMM (0x50 << OPCODE_SHIFT) -#define OPCODE_STRB_IMM (0x54 << OPCODE_SHIFT) -#define OPCODE_SUB_IMM (0x24 << OPCODE_SHIFT) -#define OPCODE_SUB_REG (0x04 << OPCODE_SHIFT) -#define OPCODE_TST_REG (0x11 << OPCODE_SHIFT) - -#define OPCODE_BFI 0xe7c00010 -#define OPCODE_BLX 0xe12fff30 -#define OPCODE_UADD8 0xe6500f90 -#define OPCODE_UADD16 0xe6500f10 -#define OPCODE_USUB8 0xe6500ff0 -#define OPCODE_USUB16 0xe6500f70 -#define OPCODE_UXTB 0xe6ef0070 -#define OPCODE_UXTH 0xe6ff0070 - -#define B_OFFSET(x) (((x) >> 2) & 0xffffff) - -#define SHIFT_TYPE_SHIFT 5 -#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT) -#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT) -#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT) -#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT) - -#define SHIFT_TYPE_IMM (0 << 4) -#define SHIFT_TYPE_REG (1 << 4) - -#define SHIFT_IMM_SHIFT 7 -#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) -#define SHIFT_LSR_IMM(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) - -#define BFI_lsb(lsb) ((lsb) << 7) -#define BFI_msb(msb) ((msb) << 16) - -#define UXTB_ROTATE(rotate) (((rotate) >> 3) << 10) - -#define MOVW_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) - -static int literal_offset = 0; -void codegen_reset_literal_pool(codeblock_t *block) -{ - literal_offset = 0; -} - -int add_literal(codeblock_t *block, uint32_t data) -{ - int c; - - if (literal_offset >= 4096) - fatal("add_literal - literal pool full\n"); - - /*Search for pre-existing value*/ - for (c = 0; c < literal_offset; c += 4) - { - if (*(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + c] == data) - return c; - } - - *(uint32_t *)&block->data[ARM_LITERAL_POOL_OFFSET + literal_offset] = data; - - literal_offset += 4; - - return literal_offset - 4; -} - - -static inline uint32_t arm_data_offset(int offset) -{ - if (offset < -0xffc || offset > 0xffc) - fatal("arm_data_offset out of range - %i\n", offset); - - if (offset >= 0) - return offset | DATA_OFFSET_UP; - return (-offset) | DATA_OFFSET_DOWN; -} - static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) { int shift = 0; @@ -163,261 +47,6 @@ static inline int in_range(void *addr, void *base) return 1; } -void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); -void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); -void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); -void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); -void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); - -void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if ((int32_t)imm < 0 && imm != 0x80000000) - { - host_arm_SUB_IMM(block, dst_reg, src_reg, -(int32_t)imm); - } - else if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); - host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); - } -} - -void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} - -void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else if (get_arm_imm(~imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); - host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); - } -} - -void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} - -void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) -{ - codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rm(src_reg) | BFI_lsb(lsb) | BFI_msb((lsb + width) - 1)); -} - -void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} -void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); -} - -void host_arm_BLX(codeblock_t *block, int addr_reg) -{ - codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); -} - -void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr) -{ - uint32_t offset = (dest_addr - (uintptr_t)&block->data[block_pos]) - 8; - - if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) - fatal("host_arm_BNE - out of range %08x %i\n", offset, offset); - - codegen_addlong(block, COND_NE | OPCODE_B | B_OFFSET(offset)); -} - -void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); - host_arm_EOR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); - } -} - -void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_EOR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} - -void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) -{ - codegen_addlong(block, COND_AL | OPCODE_LDMIA_WB | Rn(addr_reg) | reg_mask); -} - -void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) -{ - codegen_addlong(block, COND_AL | OPCODE_LDR_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); -} - -void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, dst_reg, REG_LITERAL, offset); - } -} - -void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); -} -void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_IMM(shift)); -} - -void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm) -{ - codegen_addlong(block, COND_AL | OPCODE_MOVW_IMM | Rd(dst_reg) | MOVW_IMM(imm)); -} - -void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_MVN_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); -} - -void host_arm_ORR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); - host_arm_ORR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); - } -} - -void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_ORR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} - -void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); -} - -void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) -{ - codegen_addlong(block, COND_AL | OPCODE_STMDB_WB | Rn(addr_reg) | reg_mask); -} - -void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) -{ - codegen_addlong(block, COND_AL | OPCODE_STR_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); -} - -void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) -{ - codegen_addlong(block, COND_AL | OPCODE_STRB_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); -} - -void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) -{ - uint32_t arm_imm; - - if ((int32_t)imm < 0 && imm != 0x80000000) - { - host_arm_ADD_IMM(block, dst_reg, src_reg, -(int32_t)imm); - } - else if (get_arm_imm(imm, &arm_imm)) - { - codegen_addlong(block, COND_AL | OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); - } - else - { - int offset = add_literal(block, imm); - host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); - host_arm_SUB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); - } -} - -void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); -} -void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) -{ - codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); -} - -void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2) -{ - codegen_addlong(block, COND_AL | OPCODE_TST_REG | Rn(src_reg1) | Rm(src_reg2)); -} - -void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - codegen_addlong(block, COND_AL | OPCODE_UADD8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); -} - -void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - codegen_addlong(block, COND_AL | OPCODE_UADD16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); -} - -void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - codegen_addlong(block, COND_AL | OPCODE_USUB8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); -} - -void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - codegen_addlong(block, COND_AL | OPCODE_USUB16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); -} - -void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) -{ - codegen_addlong(block, OPCODE_UXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); -} - -void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) -{ - codegen_addlong(block, OPCODE_UXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); -} - void host_arm_call(codeblock_t *block, void *dst_addr) { int offset = add_literal(block, (uintptr_t)dst_addr); @@ -593,6 +222,22 @@ static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm_BEQ(block, uop->p); + + return 0; +} + static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) { uint32_t arm_imm; @@ -646,6 +291,190 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + + return 0; +} + +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_R1, src_reg, 8); + host_arm_BL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_c_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, codegen_mem_store_byte); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, codegen_mem_store_word); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, codegen_mem_store_long); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + static int codegen_MOV(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); @@ -1015,11 +844,20 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, - + [UOP_ADD & UOP_MASK] = codegen_ADD, [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, @@ -1030,7 +868,9 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_SUB & UOP_MASK] = codegen_SUB, [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, [UOP_XOR & UOP_MASK] = codegen_XOR, - [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ }; void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) diff --git a/src/codegen_backend_x86-64.c b/src/codegen_backend_x86-64.c index 36b4567..deda8ef 100644 --- a/src/codegen_backend_x86-64.c +++ b/src/codegen_backend_x86-64.c @@ -3,6 +3,8 @@ #include "ibm.h" #include "codegen.h" #include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -13,6 +15,14 @@ #include #endif +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; + int codegen_host_reg_list[CODEGEN_HOST_REGS] = { REG_EAX, @@ -22,6 +32,183 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = static void *mem_abrt_rout; +static void build_load_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV RSI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[RSI+RCX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmemb386l + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_RDI, (uint64_t)(uintptr_t)readlookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_RDI, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 2) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 4) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_RSI, REG_RCX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x20); + //host_x86_MOV32_REG_REG(block, REG_ECX, uop->imm_data); +#else + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); +#endif + if (size == 1) + { + host_x86_CALL(block, (void *)readmemb386l); + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + } + else if (size == 2) + { + host_x86_CALL(block, (void *)readmemwl); + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + } + else if (size == 4) + { + host_x86_CALL(block, (void *)readmemll); + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + } +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x20); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [RSI+RDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writememb386l + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_R8, (uint64_t)(uintptr_t)writelookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_R8, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1) + host_x86_MOV8_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 2) + host_x86_MOV16_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 4) + host_x86_MOV32_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else + fatal("build_store_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x20); + host_x86_MOV32_REG_REG(block, REG_EDX, REG_ECX); //data + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EDI); //address +#else + //host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); //address + host_x86_MOV32_REG_REG(block, REG_ESI, REG_ECX); //data +#endif + if (size == 1) + host_x86_CALL(block, (void *)writememb386l); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x20); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4); +} + void codegen_backend_init() { int c; @@ -55,6 +242,11 @@ void codegen_backend_init() } #endif // pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = BLOCK_SIZE; + block_pos = 0; + build_loadstore_routines(&codeblock[block_current]); +// fatal("Here\n"); } static inline void call(codeblock_t *block, uintptr_t func) diff --git a/src/codegen_backend_x86-64_defs.h b/src/codegen_backend_x86-64_defs.h index dcb9a58..706c70d 100644 --- a/src/codegen_backend_x86-64_defs.h +++ b/src/codegen_backend_x86-64_defs.h @@ -6,3 +6,20 @@ #define REG_EBP 5 #define REG_ESI 6 #define REG_EDI 7 + +#define REG_RAX 0 +#define REG_RCX 1 +#define REG_RDX 2 +#define REG_RBX 3 +#define REG_RSP 4 +#define REG_RBP 5 +#define REG_RSI 6 +#define REG_RDI 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_R13 13 +#define REG_R14 14 +#define REG_R15 15 diff --git a/src/codegen_backend_x86-64_ops.c b/src/codegen_backend_x86-64_ops.c new file mode 100644 index 0000000..f508e8a --- /dev/null +++ b/src/codegen_backend_x86-64_ops.c @@ -0,0 +1,888 @@ +#ifdef __amd64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_SHR 0x28 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + block->data[block_pos++] = val; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte over! %i\n", block_pos); +// CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte2 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + block->data[block_pos++] = valc; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte3 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + block->data[block_pos++] = valc; + block->data[block_pos++] = vald; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte4 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + *(uint16_t *)&block->data[block_pos] = val; + block_pos += 2; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addword over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + *(uint32_t *)&block->data[block_pos] = val; + block_pos += 4; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + *(uint64_t *)&block->data[block_pos] = val; + block_pos += 8; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addquad over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} + +static inline void call(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + codegen_addbyte(block, 0xE8); /*CALL*/ + codegen_addlong(block, (uint32_t)diff); + } + else + { + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/ + codegen_addquad(block, func); + codegen_addbyte3(block, 0x41, 0xff, 0xd1); /*CALL R9*/ + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x04, imm_data); /*ADD EAX, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data); /*ADD dst_reg, imm_data*/ +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x05); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + else + fatal("ADD64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x00, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x24, imm_data); /*AND EAX, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data); /*AND dst_reg, imm_data*/ +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x20, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_AND16_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + call(block, (uintptr_t)p); +} + +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + else + fatal("CMP64_REG_IMM not 8-bit imm\n"); +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block->data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block->data[block_pos-1]; +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ +} +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG - bad reg\n"); + + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b]*/ + ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n"); + + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/ + (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); + codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV8_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV32_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else if (offset < (1ull << 32)) + { + codegen_addbyte2(block, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV64_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); + codegen_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV B[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV W[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV L[base_reg + index_reg], src_reg*/ +} + +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (dst_reg & 8) + fatal("host_x86_MOV32_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_addbyte2(block, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else + { + fatal("host_x86_MOV32_REG_ABS - out of range\n"); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV32_REG_BASE_INDEX reg & 8\n"); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); /*MOV dst_reg, Q[base_reg + index_reg]*/ +} + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale) +{ + if ((dst_reg & 8) || (index_reg & 8)) + fatal("host_x86_MOV64_REG_BASE_INDEX_SHIFT reg & 8\n"); + if (base_reg & 8) + codegen_addbyte4(block, 0x49, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ + else + codegen_addbyte4(block, 0x48, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg >= 8) + fatal("host_x86_MOV8_REG_IMM reg >= 4\n"); + codegen_addbyte2(block, 0xb0 | reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV16_REG_IMM reg & 8\n"); + codegen_addbyte2(block, 0x66, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV32_REG_IMM reg & 8\n"); + codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); +} + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + if (reg & 8) + { + codegen_addbyte2(block, 0x49, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV8_REG_REG - bad reg\n"); + + codegen_addbyte2(block, 0x88, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV16_REG_REG - bad reg\n"); + + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV32_REG_REG - bad reg\n"); + + codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -80 || offset < 0x80) + { + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_8 reg & 8\n"); + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_16 reg & 8\n"); + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} + +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_32_8 - bad reg\n"); + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + +// if (dst_reg & 8) +// fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + if (dst_reg & 8) + codegen_addbyte(block, 0x44); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else + fatal("host_x86_MOVZX_REG_ABS_32_8 - bad offset %i\n", offset); +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x0c, imm_data); /*OR EAX, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data); /*OR dst_reg, imm_data*/ +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x08, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ +} + +void host_x86_POP(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("POP reg & 8\n"); + codegen_addbyte(block, 0x58 | dst_reg); /*POP reg*/ +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + if (src_reg & 8) + fatal("PUSH reg & 8\n"); + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_addbyte(block, 0xc3); /*RET*/ +} + +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR32_IMM reg & 8\n"); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x2c, imm_data); /*SUB EAX, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data); /*SUB dst_reg, imm_data*/ +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + else + fatal("SUB64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_SUB8_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x28, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_SUB16_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_SUB32_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_TEST32_REG - bad reg\n"); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("TEST32_REG_IMM reg & 8\n"); + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x34, imm_data); /*XOR EAX, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data); /*XOR dst_reg, imm_data*/ +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x30, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ +} + +#endif diff --git a/src/codegen_backend_x86-64_ops.h b/src/codegen_backend_x86-64_ops.h new file mode 100644 index 0000000..6070054 --- /dev/null +++ b/src/codegen_backend_x86-64_ops.h @@ -0,0 +1,104 @@ +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg); +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index ff1f31f..3e56105 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -4,6 +4,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" #include "codegen_ir_defs.h" #define STACK_ARG0 (0) @@ -11,682 +12,6 @@ #define STACK_ARG2 (8) #define STACK_ARG3 (12) -#define RM_OP_ADD 0x00 -#define RM_OP_OR 0x08 -#define RM_OP_AND 0x20 -#define RM_OP_SUB 0x28 -#define RM_OP_XOR 0x30 - -static inline void codegen_addbyte(codeblock_t *block, uint8_t val) -{ - block->data[block_pos++] = val; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte over! %i\n", block_pos); -// CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte2 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - block->data[block_pos++] = valc; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte3 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - block->data[block_pos++] = valc; - block->data[block_pos++] = vald; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte4 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addword(codeblock_t *block, uint16_t val) -{ - *(uint16_t *)&block->data[block_pos] = val; - block_pos += 2; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addword over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addlong(codeblock_t *block, uint32_t val) -{ - *(uint32_t *)&block->data[block_pos] = val; - block_pos += 4; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addlong over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addquad(codeblock_t *block, uint64_t val) -{ - *(uint64_t *)&block->data[block_pos] = val; - block_pos += 8; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addquad over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static int is_imm8(uint32_t imm_data) -{ - if (imm_data <= 0x7f || imm_data >= 0xffffff80) - return 1; - return 0; -} - -static inline void call(codeblock_t *block, uintptr_t func) -{ - uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; - - if (diff >= -0x80000000 && diff < 0x7fffffff) - { - codegen_addbyte(block, 0xE8); /*CALL*/ - codegen_addlong(block, (uint32_t)diff); - } - else - { - codegen_addbyte2(block, 0x48, 0xb8); /*MOV RAX, func*/ - codegen_addquad(block, func); - codegen_addbyte2(block, 0xff, 0xd0); /*CALL RAX*/ - } -} - -static void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x04, imm_data); /*ADD EAX, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data); /*ADD dst_reg, imm_data*/ -} -static void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x05); /*AND AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} -static void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x00, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ -} -static void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ -} -static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ -} - -static void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x24, imm_data); /*AND EAX, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data); /*AND dst_reg, imm_data*/ -} -static void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} -static void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x20, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ -} -static void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_AND16_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ -} -static void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*AND dst_reg, src_reg_b*/ -} - -static void host_x86_CALL(codeblock_t *block, void *p) -{ - call(block, (uintptr_t)p); -} - -static void host_x86_JNZ(codeblock_t *block, void *p) -{ - codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ - codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); -} - -static void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) -{ - if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) - fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n"); - - codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/ - (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); -} - -static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ - codegen_addbyte(block, imm_data); - } - else - { - if ((uintptr_t)p >> 32) - fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); - codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ - codegen_addlong(block, (uint32_t)(uintptr_t)p); - codegen_addbyte(block, imm_data); - } -} -static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - if ((uintptr_t)p >> 32) - fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); - codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ - codegen_addlong(block, (uint32_t)(uintptr_t)p); - codegen_addlong(block, imm_data); - } -} - -static void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (src_reg & 8) - fatal("host_x86_MOV8_ABS_REG - bad reg\n"); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ - } - else - { - if ((uintptr_t)p >> 32) - fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); - codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ - codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); - codegen_addlong(block, (uint32_t)(uintptr_t)p); - } -} -static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (src_reg & 8) - fatal("host_x86_MOV32_ABS_REG - bad reg\n"); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ - } - else - { - if ((uintptr_t)p >> 32) - fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); - codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ - codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); - codegen_addlong(block, (uint32_t)(uintptr_t)p); - } -} -static void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (src_reg & 8) - fatal("host_x86_MOV64_ABS_REG - bad reg\n"); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ - } - else - { - if ((uintptr_t)p >> 32) - fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); - codegen_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/ - codegen_addlong(block, (uint32_t)(uintptr_t)p); - } -} - -static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (dst_reg & 8) - fatal("host_x86_MOV32_REG_ABS reg & 8\n"); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ - } - else - { - fatal("host_x86_MOV32_REG_ABS - out of range\n"); - codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ - codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); - codegen_addlong(block, (uint32_t)(uintptr_t)p); - } -} - -static void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) -{ - if (reg >= 8) - fatal("host_x86_MOV8_REG_IMM reg >= 4\n"); - codegen_addbyte2(block, 0xb0 | reg, imm_data); /*MOV reg, imm_data*/ -} -static void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) -{ - if (reg & 8) - fatal("host_x86_MOV16_REG_IMM reg & 8\n"); - codegen_addbyte2(block, 0x66, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ - codegen_addword(block, imm_data); -} -static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) -{ - if (reg & 8) - fatal("host_x86_MOV32_REG_IMM reg & 8\n"); - codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ - codegen_addlong(block, imm_data); -} - -static void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data) -{ - if (reg & 8) - fatal("host_x86_MOV64_REG_IMM reg & 8\n"); - codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ - codegen_addquad(block, imm_data); -} - -static void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_MOV8_REG_REG - bad reg\n"); - - codegen_addbyte2(block, 0x88, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); -} -static void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_MOV16_REG_REG - bad reg\n"); - - codegen_addbyte3(block, 0x66, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); -} -static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_MOV32_REG_REG - bad reg\n"); - - codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); -} - -static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) -{ - if (!offset) - { - codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ - codegen_addlong(block, imm_data); - } - else if (offset >= -80 || offset < 0x80) - { - codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ - codegen_addlong(block, offset); - codegen_addlong(block, imm_data); - } -} - -static void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_MOVZX_REG_32_8 - bad reg\n"); - codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ -} -static void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); - codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ -} - -static void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x0c, imm_data); /*OR EAX, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data); /*OR dst_reg, imm_data*/ -} -static void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} -static void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x08, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ -} -static void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ -} -static void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*OR dst_reg, src_reg_b*/ -} - -static void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_SUB8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x2c, imm_data); /*SUB EAX, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data); /*SUB dst_reg, imm_data*/ -} -static void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_SUB16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_SUB32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} -static void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_SUB8_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x28, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ -} -static void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_SUB16_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ -} -static void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_SUB32_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ -} - -#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) - -static void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg) -{ - if ((dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_TEST32_REG - bad reg\n"); - codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/ -} - -static void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x34, imm_data); /*XOR EAX, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data); /*XOR dst_reg, imm_data*/ -} -static void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) - fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} -static void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x30, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ -} -static void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ -} -static void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) - fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*XOR dst_reg, src_reg_b*/ -} - #define HOST_REG_GET(reg) ((IREG_GET_SIZE(reg) == IREG_SIZE_BH) ? (IREG_GET_REG((reg) & 3) | 4) : (IREG_GET_REG(reg) & 7)) #define REG_IS_L(size) (size == IREG_SIZE_L) @@ -807,6 +132,22 @@ static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_x86_JZ(block, uop->p); + + return 0; +} + static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) { #if WIN64 @@ -836,6 +177,177 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); +// fatal("Here\n"); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + static int codegen_MOV(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); @@ -1077,6 +589,15 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, @@ -1092,7 +613,9 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_SUB & UOP_MASK] = codegen_SUB, [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, [UOP_XOR & UOP_MASK] = codegen_XOR, - [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ }; void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) diff --git a/src/codegen_backend_x86.c b/src/codegen_backend_x86.c index 55430e0..b81bfce 100644 --- a/src/codegen_backend_x86.c +++ b/src/codegen_backend_x86.c @@ -3,6 +3,8 @@ #include "ibm.h" #include "codegen.h" #include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -13,6 +15,14 @@ #include #endif +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; + int codegen_host_reg_list[CODEGEN_HOST_REGS] = { REG_EAX, @@ -22,6 +32,164 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = static void *mem_abrt_rout; +static void build_load_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV ESI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[ESI+ECX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmemb386l + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, readlookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 2) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 4) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_ESI, REG_ECX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + if (size == 1) + host_x86_CALL(block, (void *)readmemb386l); + else if (size == 2) + host_x86_CALL(block, (void *)readmemwl); + else if (size == 4) + host_x86_CALL(block, (void *)readmemll); + host_x86_POP(block, REG_ECX); + if (size == 1) + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + else if (size == 2) + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + else if (size == 4) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [ESI+EDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writememb386l + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, writelookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1) + host_x86_MOV8_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 2) + host_x86_MOV16_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 4) + host_x86_MOV32_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else + fatal("build_store_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + host_x86_PUSH(block, REG_EDI); + if (size == 1) + host_x86_CALL(block, (void *)writememb386l); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); + host_x86_POP(block, REG_EDI); + host_x86_POP(block, REG_ECX); + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4); +} + void codegen_backend_init() { int c; @@ -67,6 +235,10 @@ void codegen_backend_init() addbyte(0x5d); /*POP EBP*/ addbyte(0x5b); /*POP EDX*/ addbyte(0xC3); /*RET*/ + + block_pos = 64; + build_loadstore_routines(&codeblock[block_current]); + //fatal("Here\n"); asm( "fstcw %0\n" diff --git a/src/codegen_backend_x86_defs.h b/src/codegen_backend_x86_defs.h index f28915e..37e4160 100644 --- a/src/codegen_backend_x86_defs.h +++ b/src/codegen_backend_x86_defs.h @@ -12,4 +12,12 @@ #define CODEGEN_HOST_REGS 3 +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; + #endif diff --git a/src/codegen_backend_x86_ops.c b/src/codegen_backend_x86_ops.c new file mode 100644 index 0000000..1447338 --- /dev/null +++ b/src/codegen_backend_x86_ops.c @@ -0,0 +1,779 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_SHR 0x28 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + block->data[block_pos++] = val; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte over! %i\n", block_pos); +// CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte2 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + block->data[block_pos++] = valc; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte3 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + block->data[block_pos++] = vala; + block->data[block_pos++] = valb; + block->data[block_pos++] = valc; + block->data[block_pos++] = vald; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte4 over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + *(uint16_t *)&block->data[block_pos] = val; + block_pos += 2; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addword over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + *(uint32_t *)&block->data[block_pos] = val; + block_pos += 4; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + *(uint64_t *)&block->data[block_pos] = val; + block_pos += 8; + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addquad over! %i\n", block_pos); + CPU_BLOCK_END(); + } +} + +static int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} + +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, int src_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x03, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x03); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x04, imm_data); /*ADD AL, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | dst_reg, imm_data); /*ADD dst_reg, imm_data*/ +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x05); /*ADD AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x00, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x24, imm_data); /*AND AL, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | dst_reg, imm_data); /*AND dst_reg, imm_data*/ +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_AND16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_AND8_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x20, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_AND16_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_AND32_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x21, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + codegen_addbyte(block, 0xe8); /*CALL*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); +} + +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block->data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block->data[block_pos-1]; +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ +} + +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b]*/ +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV B[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV W[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV L[base_reg + idx_reg], src_reg*/ +} + +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift) +{ + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (shift << 6) | (idx_reg << 3) | 0x05); /*MOV dst_reg, [p + idx_reg << shift]*/ + codegen_addlong(block, (uint32_t)p); +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOV dst_reg, L[base_reg + idx_reg]*/ +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + codegen_addbyte2(block, 0xb0 + dst_reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (!imm_data) + { + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_addbyte2(block, 0x66, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (!imm_data) + { + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_addbyte(block, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte2(block, 0x88, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -80 || offset < 0x80) + { + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_addbyte3(block, 0x0f, 0xb6, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_addbyte3(block, 0x0f, 0xb7, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, B[base_reg + idx_reg]*/ +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, W[base_reg + idx_reg]*/ +} + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_OR8_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x08, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_OR16_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x09, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x0c, imm_data); /*OR AL, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | dst_reg, imm_data); /*OR dst_reg, imm_data*/ +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_POP(codeblock_t *block, int src_reg) +{ + codegen_addbyte(block, 0x58 | src_reg); /*POP reg*/ +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_addbyte(block, 0xc3); /*RET*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_SUB8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x2c, imm_data); /*SUB AL, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | dst_reg, imm_data); /*SUB dst_reg, imm_data*/ +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_SUB16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_SUB32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_SUB8_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x28, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_SUB16_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_SUB32_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ +} + +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_XOR8_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x30, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_XOR16_REG_REG - dst_reg != src_reg_a\n"); + + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg\n"); + + if (dst_reg == REG_EAX) + codegen_addbyte2(block, 0x34, imm_data); /*XOR AL, imm_data*/ + else + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | dst_reg, imm_data); /*XOR dst_reg, imm_data*/ +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + else if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +#endif diff --git a/src/codegen_backend_x86_ops.h b/src/codegen_backend_x86_ops.h new file mode 100644 index 0000000..cf4a793 --- /dev/null +++ b/src/codegen_backend_x86_ops.h @@ -0,0 +1,100 @@ +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, int src_reg, void *p); + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg_a, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); + +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST32_REG_IMM(codeblock_t *block, int src_host_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index 0f68a25..e043cc9 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -4,6 +4,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" #include "codegen_ir_defs.h" #define STACK_ARG0 (0) @@ -11,616 +12,6 @@ #define STACK_ARG2 (8) #define STACK_ARG3 (12) -#define RM_OP_ADD 0x00 -#define RM_OP_OR 0x08 -#define RM_OP_AND 0x20 -#define RM_OP_SUB 0x28 -#define RM_OP_XOR 0x30 - -static inline void codegen_addbyte(codeblock_t *block, uint8_t val) -{ - block->data[block_pos++] = val; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte over! %i\n", block_pos); -// CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte2 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - block->data[block_pos++] = valc; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte3 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} -static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) -{ - block->data[block_pos++] = vala; - block->data[block_pos++] = valb; - block->data[block_pos++] = valc; - block->data[block_pos++] = vald; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addbyte4 over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addword(codeblock_t *block, uint16_t val) -{ - *(uint16_t *)&block->data[block_pos] = val; - block_pos += 2; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addword over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addlong(codeblock_t *block, uint32_t val) -{ - *(uint32_t *)&block->data[block_pos] = val; - block_pos += 4; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addlong over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static inline void codegen_addquad(codeblock_t *block, uint64_t val) -{ - *(uint64_t *)&block->data[block_pos] = val; - block_pos += 8; - if (block_pos >= BLOCK_MAX) - { - fatal("codegen_addquad over! %i\n", block_pos); - CPU_BLOCK_END(); - } -} - -static int is_imm8(uint32_t imm_data) -{ - if (imm_data <= 0x7f || imm_data >= 0xffffff80) - return 1; - return 0; -} - -static void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x04, imm_data); /*ADD AL, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | dst_reg, imm_data); /*ADD dst_reg, imm_data*/ -} -static void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x05); /*ADD AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - -static void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_ADD8_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x00, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ -} -static void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_ADD16_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x01, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ -} -static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ -} - -static void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_AND8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x24, imm_data); /*AND AL, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | dst_reg, imm_data); /*AND dst_reg, imm_data*/ -} -static void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_AND16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - -static void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_AND8_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x20, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ -} -static void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_AND16_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x21, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ -} -static void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_AND32_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x21, 0xc0 | dst_reg | (src_reg_b << 3)); /*AND dst_reg, src_reg_b*/ -} - -static void host_x86_CALL(codeblock_t *block, void *p) -{ - codegen_addbyte(block, 0xe8); /*CALL*/ - codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); -} - -static void host_x86_JNZ(codeblock_t *block, void *p) -{ - codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ - codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); -} - -static void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) -{ - codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ -} - -static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ - codegen_addbyte(block, imm_data); - } - else - { - codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addbyte(block, imm_data); - } -} -static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addlong(block, imm_data); - } -} - -static void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ - } - else - { - codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ - codegen_addbyte(block, 0x05 | (src_reg << 3)); - codegen_addlong(block, (uint32_t)p); - } -} -static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ - } - else - { - codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ - codegen_addbyte(block, 0x05 | (src_reg << 3)); - codegen_addlong(block, (uint32_t)p); - } -} - -static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) -{ - int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); - - if (offset >= -128 && offset < 127) - { - codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ - } - else - { - codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ - codegen_addbyte(block, 0x05 | (dst_reg << 3)); - codegen_addlong(block, (uint32_t)p); - } -} - -static void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) -{ - codegen_addbyte2(block, 0xb0 + dst_reg, imm_data); /*MOV reg, imm_data*/ -} -static void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) -{ - if (!imm_data) - { - codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ - } - else - { - codegen_addbyte2(block, 0x66, 0xb8 + dst_reg); /*MOV reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) -{ - if (!imm_data) - { - codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ - } - else - { - codegen_addbyte(block, 0xb8 + dst_reg); /*MOV reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - -static void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - codegen_addbyte2(block, 0x88, 0xc0 | dst_reg | (src_reg << 3)); -} -static void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - codegen_addbyte3(block, 0x66, 0x89, 0xc0 | dst_reg | (src_reg << 3)); -} -static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) -{ - codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3)); -} - -static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) -{ - if (!offset) - { - codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ - codegen_addlong(block, imm_data); - } - else if (offset >= -80 || offset < 0x80) - { - codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ - codegen_addlong(block, offset); - codegen_addlong(block, imm_data); - } -} - -static void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) -{ - codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ -} -static void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) -{ - codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ -} - -static void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_OR8_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x08, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ -} -static void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_OR16_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x09, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ -} -static void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x09, 0xc0 | dst_reg | (src_reg_b << 3)); /*OR dst_reg, src_reg_b*/ -} - -static void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_OR8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x0c, imm_data); /*OR AL, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | dst_reg, imm_data); /*OR dst_reg, imm_data*/ -} -static void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_OR16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_OR32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - -#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) - -static void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_SUB8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x2c, imm_data); /*SUB AL, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | dst_reg, imm_data); /*SUB dst_reg, imm_data*/ -} -static void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_SUB16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_SUB32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - -static void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_SUB8_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x28, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ -} -static void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_SUB16_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ -} -static void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_SUB32_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ -} - -static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) -{ - codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ -} - -static void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_XOR8_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x30, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ -} -static void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_XOR16_REG_REG - dst_reg != src_reg_a\n"); - - codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ -} -static void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) -{ - if (dst_reg != src_reg_a) - fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg_a\n"); - - codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (src_reg_b << 3)); /*XOR dst_reg, src_reg_b*/ -} - -static void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_XOR8_REG_IMM - dst_reg != src_reg\n"); - - if (dst_reg == REG_EAX) - codegen_addbyte2(block, 0x34, imm_data); /*XOR AL, imm_data*/ - else - codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | dst_reg, imm_data); /*XOR dst_reg, imm_data*/ -} -static void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_XOR16_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ - codegen_addword(block, imm_data); - } - else - { - codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ - codegen_addword(block, imm_data); - } -} -static void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) -{ - if (dst_reg != src_reg) - fatal("host_x86_XOR32_REG_IMM - dst_reg != src_reg\n"); - - if (is_imm8(imm_data)) - codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ - else if (dst_reg == REG_EAX) - { - codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ - codegen_addlong(block, imm_data); - } - else - { - codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ - codegen_addlong(block, imm_data); - } -} - - /*void codegen_debug() { pclog(" %04x:%04x : %08x %08x %08x %08x\n", CS, cpu_state.pc, AX, BX, CX, DX); @@ -752,6 +143,22 @@ static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_x86_JZ(block, uop->p); + + return 0; +} + static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) { host_x86_MOV32_STACK_IMM(block, STACK_ARG0, uop->imm_data); @@ -773,6 +180,176 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); + + return 0; +} + static int codegen_MOV(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); @@ -1010,6 +587,15 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, @@ -1025,7 +611,9 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_SUB & UOP_MASK] = codegen_SUB, [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, [UOP_XOR & UOP_MASK] = codegen_XOR, - [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ }; void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) diff --git a/src/codegen_ir.c b/src/codegen_ir.c index 1d89807..8d81db8 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -27,9 +27,14 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) // pclog("uOP %i : %08x\n", c, uop->type); + if (uop->type & UOP_TYPE_BARRIER) + codegen_reg_flush_invalidate(ir, block); + else if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + if (uop->type & UOP_TYPE_PARAMS_REGS) { - codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b); + codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); if (uop->src_reg_a.reg != IREG_INVALID) { uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); @@ -38,19 +43,22 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) { uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL); } + if (uop->src_reg_c.reg != IREG_INVALID) + { + uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL); + } if (uop->dest_reg_a.reg != IREG_INVALID) { uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); } } - if (uop->type & UOP_TYPE_BARRIER) - codegen_reg_flush(ir, block); - + if (!uop_handlers[uop->type & UOP_MASK]) + fatal("!uop_handlers[uop->type & UOP_MASK]\n"); uop_handlers[uop->type & UOP_MASK](block, uop); } - codegen_reg_flush(ir, block); + codegen_reg_flush_invalidate(ir, block); codegen_backend_epilogue(block); diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index 04ee628..7a1d947 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -6,9 +6,17 @@ #define UOP_REG(reg, size, version) ((reg) | (size) | (version << 8)) /*uOP is a barrier. All previous uOPs must have completed before this one executes. - All registers must have been written back or discarded*/ + All registers must have been written back or discarded. + This should be used when calling external functions that may change any emulated + registers.*/ #define UOP_TYPE_BARRIER (1 << 31) +/*uOP is a barrier. All previous uOPs must have completed before this one executes. + All registers must have been written back, but do not have to be discarded. + This should be used when calling functions that preserve registers, but can cause + the code block to exit (eg memory load/store functions).*/ +#define UOP_TYPE_ORDER_BARRIER (1 << 27) + /*uOP uses source and dest registers*/ #define UOP_TYPE_PARAMS_REGS (1 << 28) /*uOP uses pointer*/ @@ -62,8 +70,24 @@ #define UOP_XOR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x39) /*UOP_XOR_IMM - dest_reg = src_reg_a ^ immediate*/ #define UOP_XOR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x3a) +/*UOP_MEM_LOAD_ABS - dest_reg = src_reg_a:[immediate]*/ +#define UOP_MEM_LOAD_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x40 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_REG - dest_reg = src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_REG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x41 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_ABS - src_reg_a:[immediate] = src_reg_b*/ +#define UOP_MEM_STORE_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x42 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_REG - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_REG (UOP_TYPE_PARAMS_REGS | 0x43 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_8 - byte src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_8 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x44 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_16 - word src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x45 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_32 - long src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_32 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x46 | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_JZ - if (src_reg_a == imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JZ (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x48 | UOP_TYPE_ORDER_BARRIER) -#define UOP_MAX 0x3b +#define UOP_MAX 0x49 #define UOP_MASK 0xffff @@ -73,10 +97,11 @@ typedef struct uop_t ir_reg_t dest_reg_a; ir_reg_t src_reg_a; ir_reg_t src_reg_b; + ir_reg_t src_reg_c; uint32_t imm_data; void *p; ir_host_reg_t dest_reg_a_real; - ir_host_reg_t src_reg_a_real, src_reg_b_real; + ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real; } uop_t; #define UOP_NR_MAX 4096 @@ -99,7 +124,8 @@ static inline uop_t *uop_alloc(ir_data_t *ir) uop->dest_reg_a = invalid_ir_reg; uop->src_reg_a = invalid_ir_reg; uop->src_reg_b = invalid_ir_reg; - + uop->src_reg_c = invalid_ir_reg; + return uop; } @@ -179,6 +205,26 @@ static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int uop->imm_data = imm; } +static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); +} + static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) { uop_t *uop = uop_alloc(ir); @@ -204,6 +250,16 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p uop->imm_data = imm; } +static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->p = p; + uop->imm_data = imm; +} + #define uop_LOAD_FUNC_ARG_REG(ir, arg, reg) uop_gen_reg_src1(UOP_LOAD_FUNC_ARG_0 + arg, ir, reg) #define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm) @@ -223,6 +279,16 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p #define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p) #define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p) +#define uop_CMP_IMM_JZ(ir, src_reg, imm, p) uop_gen_reg_src_pointer_imm(UOP_CMP_IMM_JZ, ir, src_reg, p, imm) + +#define uop_MEM_LOAD_ABS(ir, dst_reg, seg_reg, imm) uop_gen_reg_dst_src_imm(UOP_MEM_LOAD_ABS, ir, dst_reg, seg_reg, imm) +#define uop_MEM_LOAD_REG(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2(UOP_MEM_LOAD_REG, ir, dst_reg, seg_reg, addr_reg) +#define uop_MEM_STORE_ABS(ir, seg_reg, imm, src_reg) uop_gen_reg_src2_imm(UOP_MEM_STORE_ABS, ir, seg_reg, src_reg, imm) +#define uop_MEM_STORE_REG(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3(UOP_MEM_STORE_REG, ir, seg_reg, addr_reg, src_reg) +#define uop_MEM_STORE_IMM_8(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_8, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_16(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_16, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_32(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_32, ir, seg_reg, addr_reg, imm) + #define uop_MOV(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV, ir, dst_reg, src_reg) #define uop_MOV_IMM(ir, reg, imm) uop_gen_reg_dst_imm(UOP_MOV_IMM, ir, reg, imm) #define uop_MOV_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_PTR, ir, reg, p) diff --git a/src/codegen_ops.c b/src/codegen_ops.c index caaf3ff..6fc74b4 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -22,10 +22,10 @@ RecompOpFn recomp_opcodes[512] = /*80*/ rop80, rop81_w, rop80, rop83_w, NULL, NULL, NULL, NULL, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, NULL, NULL, NULL, NULL, /*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_AX_abs, ropMOV_abs_AL, ropMOV_abs_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, -/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -44,10 +44,10 @@ RecompOpFn recomp_opcodes[512] = /*80*/ rop80, rop81_l, rop80, rop83_l, NULL, NULL, NULL, NULL, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, NULL, NULL, NULL, NULL, /*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_EAX_abs, ropMOV_abs_AL, ropMOV_abs_EAX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, -/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL diff --git a/src/codegen_ops_mov.c b/src/codegen_ops_mov.c index b8bb8aa..c7d906d 100644 --- a/src/codegen_ops_mov.c +++ b/src/codegen_ops_mov.c @@ -36,43 +36,64 @@ uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32 uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int dest_reg = fetchdat & 7; + int src_reg = (fetchdat >> 3) & 7; if ((fetchdat & 0xc0) == 0xc0) { - int src_reg = (fetchdat >> 3) & 7; + int dest_reg = fetchdat & 7; uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_8(src_reg)); + } return op_pc + 1; } uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int dest_reg = fetchdat & 7; + int src_reg = (fetchdat >> 3) & 7; if ((fetchdat & 0xc0) == 0xc0) { - int src_reg = (fetchdat >> 3) & 7; + int dest_reg = fetchdat & 7; uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_16(src_reg)); + } return op_pc + 1; } uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int dest_reg = fetchdat & 7; + int src_reg = (fetchdat >> 3) & 7; if ((fetchdat & 0xc0) == 0xc0) { - int src_reg = (fetchdat >> 3) & 7; + int dest_reg = fetchdat & 7; uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_32(src_reg)); + } return op_pc + 1; } @@ -86,7 +107,15 @@ uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_8(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + CPU_BLOCK_END(); + } return op_pc + 1; } @@ -100,7 +129,14 @@ uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_16(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } return op_pc + 1; } @@ -114,7 +150,176 @@ uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); } else - return 0; + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_32(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } return op_pc + 1; } + +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AL, ireg_seg_base(op_ea_seg), addr); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AX, ireg_seg_base(op_ea_seg), addr); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_EAX, ireg_seg_base(op_ea_seg), addr); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AL); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_EAX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint8_t imm; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadb(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_8(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadb(cs + op_pc + 1); + uop_MEM_STORE_IMM_8(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + return op_pc + 2; +} +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint16_t imm; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadw(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_16(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadw(cs + op_pc + 1); + uop_MEM_STORE_IMM_16(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + return op_pc + 3; +} +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint32_t imm; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadl(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_32(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadl(cs + op_pc + 1); + uop_MEM_STORE_IMM_32(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + return op_pc + 5; +} diff --git a/src/codegen_ops_mov.h b/src/codegen_ops_mov.h index cf8b31f..78442b4 100644 --- a/src/codegen_ops_mov.h +++ b/src/codegen_ops_mov.h @@ -1,9 +1,22 @@ uint32_t ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_reg.c b/src/codegen_reg.c index 43027f3..28a08be 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -56,6 +56,13 @@ struct [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins}, [IREG_cycles] = {REG_DWORD, &cpu_state._cycles}, + + [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base}, + [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base}, + [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base}, + [IREG_FS_base] = {REG_DWORD, &cpu_state.seg_fs.base}, + [IREG_GS_base] = {REG_DWORD, &cpu_state.seg_gs.base}, + [IREG_SS_base] = {REG_DWORD, &cpu_state.seg_ss.base}, /*Temporary registers are stored on the stack, and are not guaranteed to be preserved across uOPs. They will not be written back if they will @@ -63,7 +70,7 @@ struct [IREG_temp0] = {REG_DWORD, NULL}, [IREG_temp1] = {REG_DWORD, NULL}, [IREG_temp2] = {REG_DWORD, NULL}, - [IREG_temp3] = {REG_DWORD, NULL} + [IREG_temp3] = {REG_DWORD, NULL}, }; void codegen_reg_reset() @@ -103,7 +110,7 @@ static void codegen_reg_load(codeblock_t *block, int c, ir_reg_t ir_reg) //pclog(" codegen_reg_load: c=%i reg=%02x.%i\n", c, host_regs[c].reg,host_regs[c].version); } -static void codegen_reg_writeback(codeblock_t *block, int c) +static void codegen_reg_writeback(codeblock_t *block, int c, int invalidate) { int ir_reg = IREG_GET_REG(host_regs[c].reg); @@ -125,11 +132,12 @@ static void codegen_reg_writeback(codeblock_t *block, int c) fatal("codegen_reg_flush - native_size=%i\n", ireg_data[ir_reg].native_size); } - host_regs[c] = invalid_ir_reg; + if (invalidate) + host_regs[c] = invalid_ir_reg; host_reg_dirty[c] = 0; } -void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b) +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c) { int c; int dest_reference = 0; @@ -146,6 +154,8 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_ dest_reference++; if (!ir_reg_is_invalid(src_reg_b) && IREG_GET_REG(src_reg_b.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_b.version == dest_reg_a.version-1) dest_reference++; + if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(src_reg_c.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_c.version == dest_reg_a.version-1) + dest_reference++; } for (c = 0; c < CODEGEN_HOST_REGS; c++) { @@ -161,6 +171,12 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_ fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_b.version\n"); host_regs_locked |= (1 << c); } + if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(src_reg_c.reg)) + { + if (host_regs[c].version != src_reg_c.version) + fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_c.version\n"); + host_regs_locked |= (1 << c); + } if (!ir_reg_is_invalid(dest_reg_a) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(dest_reg_a.reg)) { if (host_regs[c].version == dest_reg_a.version || (host_regs[c].version == (dest_reg_a.version-1) && reg_version_refcount[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version] == dest_reference)) @@ -196,7 +212,7 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in if (c == CODEGEN_HOST_REGS) fatal("codegen_reg_alloc_read_reg - out of registers\n"); if (host_reg_dirty[c]) - codegen_reg_writeback(block, c); + codegen_reg_writeback(block, c, 1); // pclog(" load %i\n", c); codegen_reg_load(block, c, ir_reg); host_regs_locked |= (1 << c); @@ -277,7 +293,7 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) if (c == CODEGEN_HOST_REGS) fatal("codegen_reg_alloc_write_reg - out of registers\n"); if (host_reg_dirty[c]) - codegen_reg_writeback(block, c); + codegen_reg_writeback(block, c, 1); } } @@ -289,6 +305,19 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) } void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) +{ + int c; + + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!ir_reg_is_invalid(host_regs[c]) && host_reg_dirty[c]) + { + codegen_reg_writeback(block, c, 0); + } + } +} + +void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) { int c; @@ -296,7 +325,7 @@ void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) { if (!ir_reg_is_invalid(host_regs[c])) { - codegen_reg_writeback(block, c); + codegen_reg_writeback(block, c, 1); } } } diff --git a/src/codegen_reg.h b/src/codegen_reg.h index b8f4de5..1e3d339 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -42,13 +42,20 @@ enum IREG_ins = 19, IREG_cycles = 20, + IREG_CS_base = 21, + IREG_DS_base = 22, + IREG_ES_base = 23, + IREG_FS_base = 24, + IREG_GS_base = 25, + IREG_SS_base = 26, + /*Temporary registers are stored on the stack, and are not guaranteed to be preserved across uOPs. They will not be written back if they will not be read again.*/ - IREG_temp0 = 21, - IREG_temp1 = 22, - IREG_temp2 = 23, - IREG_temp3 = 24, + IREG_temp0 = 27, + IREG_temp1 = 28, + IREG_temp2 = 29, + IREG_temp3 = 30, IREG_COUNT, @@ -82,6 +89,24 @@ enum #define IREG_16(reg) ((reg) + IREG_AX) #define IREG_32(reg) ((reg) + IREG_EAX) +static inline int ireg_seg_base(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_base; + if (seg == &cpu_state.seg_ds) + return IREG_DS_base; + if (seg == &cpu_state.seg_es) + return IREG_ES_base; + if (seg == &cpu_state.seg_fs) + return IREG_FS_base; + if (seg == &cpu_state.seg_gs) + return IREG_GS_base; + if (seg == &cpu_state.seg_ss) + return IREG_SS_base; + fatal("ireg_seg_base : unknown segment\n"); + return 0; +} + extern uint8_t reg_last_version[IREG_COUNT]; extern uint8_t reg_version_refcount[IREG_COUNT][256]; @@ -131,10 +156,13 @@ static inline ir_reg_t codegen_reg_write(int reg) struct ir_data_t; void codegen_reg_reset(); +/*Write back all dirty registers*/ void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block); +/*Write back and evict all registers*/ +void codegen_reg_flush_invalidate(struct ir_data_t *ir, codeblock_t *block); /*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/ -void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b); +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c); ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx); ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg);