#![allow(non_snake_case)] use codegen; use cpu_context::CpuContext; use global_pointers; use jit::JitContext; use modrm; use prefix::SEG_PREFIX_ZERO; use prefix::{PREFIX_66, PREFIX_67, PREFIX_F2, PREFIX_F3}; use regs; use regs::{AX, BP, BX, CX, DI, DX, SI, SP}; use regs::{CS, DS, ES, FS, GS, SS}; use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP}; use wasmgen::module_init::WasmBuilder; use wasmgen::wasm_util::WasmBuf; pub fn jit_instruction(cpu: &mut CpuContext, builder: &mut WasmBuilder, instr_flags: &mut u32) { cpu.prefixes = 0; let start_of_current_instruction = cpu.eip; let ctx = &mut JitContext { cpu, builder, start_of_current_instruction, }; ::gen::jit::jit( ctx.cpu.read_imm8() as u32 | (ctx.cpu.osize_32() as u32) << 8, ctx, instr_flags, ); } pub fn jit_handle_prefix(ctx: &mut JitContext, instr_flags: &mut u32) { ::gen::jit::jit( ctx.cpu.read_imm8() as u32 | (ctx.cpu.osize_32() as u32) << 8, ctx, instr_flags, ); codegen::gen_clear_prefixes(ctx); } pub fn jit_handle_segment_prefix(segment: u32, ctx: &mut JitContext, instr_flags: &mut u32) { dbg_assert!(segment <= 5); ctx.cpu.prefixes |= segment + 1; // TODO: Could merge multiple prefix updates into one codegen::gen_add_prefix_bits(ctx, segment + 1); jit_handle_prefix(ctx, instr_flags) } pub fn instr16_0F_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ::gen::jit0f_16::jit(ctx.cpu.read_imm8(), ctx, instr_flags) } pub fn instr32_0F_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ::gen::jit0f_32::jit(ctx.cpu.read_imm8(), ctx, instr_flags) } pub fn instr_26_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(ES, ctx, instr_flags) } pub fn instr_2E_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(CS, ctx, instr_flags) } pub fn instr_36_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(SS, ctx, instr_flags) } pub fn instr_3E_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(DS, ctx, instr_flags) } pub fn instr_64_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(FS, ctx, instr_flags) } pub fn instr_65_jit(ctx: &mut JitContext, instr_flags: &mut u32) { jit_handle_segment_prefix(GS, ctx, instr_flags) } pub fn instr_66_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ctx.cpu.prefixes |= PREFIX_66; // TODO: Could merge multiple prefix updates into one codegen::gen_add_prefix_bits(ctx, PREFIX_66); jit_handle_prefix(ctx, instr_flags) } pub fn instr_67_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ctx.cpu.prefixes |= PREFIX_67; // TODO: Could merge multiple prefix updates into one codegen::gen_add_prefix_bits(ctx, PREFIX_67); jit_handle_prefix(ctx, instr_flags) } pub fn instr_F0_jit(ctx: &mut JitContext, instr_flags: &mut u32) { // lock: Ignore jit_handle_prefix(ctx, instr_flags) } pub fn instr_F2_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ctx.cpu.prefixes |= PREFIX_F2; // string/sse prefix: Don't generate code to update prefixes at runtime. This means runtime // instructions can't inspect the prefixes for this flags jit_handle_prefix(ctx, instr_flags) } pub fn instr_F3_jit(ctx: &mut JitContext, instr_flags: &mut u32) { ctx.cpu.prefixes |= PREFIX_F3; // string/sse prefix: Don't generate code to update prefixes at runtime. This means runtime // instructions can't inspect the prefixes for this flags jit_handle_prefix(ctx, instr_flags) } fn push16_reg_jit(ctx: &mut JitContext, r: u32) { codegen::gen_get_reg16(ctx.builder, r); let value_local = ctx.builder.set_new_local(); codegen::gen_push16(ctx, &value_local); ctx.builder.free_local(value_local); } fn push32_reg_jit(ctx: &mut JitContext, r: u32) { ctx.builder .instruction_body .load_aligned_i32(global_pointers::get_reg32_offset(r)); let value_local = ctx.builder.set_new_local(); codegen::gen_push32(ctx, &value_local); ctx.builder.free_local(value_local); } fn push16_imm_jit(ctx: &mut JitContext, imm: u32) { ctx.builder.instruction_body.const_i32(imm as i32); let value_local = ctx.builder.set_new_local(); codegen::gen_push16(ctx, &value_local); ctx.builder.free_local(value_local); } fn push32_imm_jit(ctx: &mut JitContext, imm: u32) { ctx.builder.instruction_body.const_i32(imm as i32); let value_local = ctx.builder.set_new_local(); codegen::gen_push32(ctx, &value_local); ctx.builder.free_local(value_local); } fn push16_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read16(ctx); let value_local = ctx.builder.set_new_local(); codegen::gen_push16(ctx, &value_local); ctx.builder.free_local(value_local); } fn push32_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read32(ctx); let value_local = ctx.builder.set_new_local(); codegen::gen_push32(ctx, &value_local); ctx.builder.free_local(value_local); } fn pop16_reg_jit(ctx: &mut JitContext, reg: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(reg) as i32); codegen::gen_pop16(ctx); ctx.builder.instruction_body.store_aligned_u16(0); } fn pop32_reg_jit(ctx: &mut JitContext, reg: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(reg) as i32); codegen::gen_pop32s(ctx); ctx.builder.instruction_body.store_aligned_i32(0); } macro_rules! define_instruction_read8( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); codegen::gen_get_reg8(ctx.builder, r); codegen::gen_call_fn2(ctx.builder, $fn) } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg8(ctx.builder, r1); codegen::gen_get_reg8(ctx.builder, r2); codegen::gen_call_fn2(ctx.builder, $fn) } ) ); macro_rules! define_instruction_read16( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read16(ctx); codegen::gen_get_reg16(ctx.builder, r); codegen::gen_call_fn2(ctx.builder, $fn) } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg16(ctx.builder, r1); codegen::gen_get_reg16(ctx.builder, r2); codegen::gen_call_fn2(ctx.builder, $fn) } ) ); macro_rules! define_instruction_read32( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read32(ctx); codegen::gen_get_reg32(ctx.builder, r); codegen::gen_call_fn2(ctx.builder, $fn) } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg32(ctx.builder, r1); codegen::gen_get_reg32(ctx.builder, r2); codegen::gen_call_fn2(ctx.builder, $fn) } ) ); macro_rules! define_instruction_write_reg8( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg8_offset(r) as i32); codegen::gen_get_reg8(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_u8(0); } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg8_offset(r2) as i32); codegen::gen_get_reg8(ctx.builder, r2); codegen::gen_get_reg8(ctx.builder, r1); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_u8(0); } ) ); macro_rules! define_instruction_write_reg16( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg16_offset(r) as i32); codegen::gen_get_reg16(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read16(ctx); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg16_offset(r2) as i32); codegen::gen_get_reg16(ctx.builder, r2); codegen::gen_get_reg16(ctx.builder, r1); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_aligned_u16(0); } ) ); macro_rules! define_instruction_write_reg32( ($fn:expr, $name_mem:ident, $name_reg:ident) => ( pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg32_offset(r) as i32); codegen::gen_get_reg32(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read32(ctx); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) { ctx.builder.instruction_body.const_i32(global_pointers::get_reg32_offset(r2) as i32); codegen::gen_get_reg32(ctx.builder, r2); codegen::gen_get_reg32(ctx.builder, r1); codegen::gen_call_fn2_ret(ctx.builder, $fn); ctx.builder.instruction_body.store_aligned_i32(0); } ) ); define_instruction_write_reg8!("add8", instr_02_mem_jit, instr_02_reg_jit); define_instruction_write_reg16!("add16", instr16_03_mem_jit, instr16_03_reg_jit); define_instruction_write_reg32!("add32", instr32_03_mem_jit, instr32_03_reg_jit); define_instruction_write_reg8!("or8", instr_0A_mem_jit, instr_0A_reg_jit); define_instruction_write_reg16!("or16", instr16_0B_mem_jit, instr16_0B_reg_jit); define_instruction_write_reg32!("or32", instr32_0B_mem_jit, instr32_0B_reg_jit); define_instruction_write_reg8!("adc8", instr_12_mem_jit, instr_12_reg_jit); define_instruction_write_reg16!("adc16", instr16_13_mem_jit, instr16_13_reg_jit); define_instruction_write_reg32!("adc32", instr32_13_mem_jit, instr32_13_reg_jit); define_instruction_write_reg8!("sbb8", instr_1A_mem_jit, instr_1A_reg_jit); define_instruction_write_reg16!("sbb16", instr16_1B_mem_jit, instr16_1B_reg_jit); define_instruction_write_reg32!("sbb32", instr32_1B_mem_jit, instr32_1B_reg_jit); define_instruction_write_reg8!("and8", instr_22_mem_jit, instr_22_reg_jit); define_instruction_write_reg16!("and16", instr16_23_mem_jit, instr16_23_reg_jit); define_instruction_write_reg32!("and32", instr32_23_mem_jit, instr32_23_reg_jit); define_instruction_write_reg8!("sub8", instr_2A_mem_jit, instr_2A_reg_jit); define_instruction_write_reg16!("sub16", instr16_2B_mem_jit, instr16_2B_reg_jit); define_instruction_write_reg32!("sub32", instr32_2B_mem_jit, instr32_2B_reg_jit); define_instruction_write_reg8!("xor8", instr_32_mem_jit, instr_32_reg_jit); define_instruction_write_reg16!("xor16", instr16_33_mem_jit, instr16_33_reg_jit); define_instruction_write_reg32!("xor32", instr32_33_mem_jit, instr32_33_reg_jit); define_instruction_read8!("cmp8", instr_38_mem_jit, instr_38_reg_jit); define_instruction_read16!("cmp16", instr16_39_mem_jit, instr16_39_reg_jit); define_instruction_read32!("cmp32", instr32_39_mem_jit, instr32_39_reg_jit); pub fn instr_3A_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_get_reg8(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); codegen::gen_call_fn2(ctx.builder, "cmp8") } pub fn instr_3A_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg8(ctx.builder, r2); codegen::gen_get_reg8(ctx.builder, r1); codegen::gen_call_fn2(ctx.builder, "cmp8") } pub fn instr16_3B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_get_reg16(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read16(ctx); codegen::gen_call_fn2(ctx.builder, "cmp16") } pub fn instr16_3B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg16(ctx.builder, r2); codegen::gen_get_reg16(ctx.builder, r1); codegen::gen_call_fn2(ctx.builder, "cmp16") } pub fn instr32_3B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_get_reg32(ctx.builder, r); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read32(ctx); codegen::gen_call_fn2(ctx.builder, "cmp32") } pub fn instr32_3B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_get_reg32(ctx.builder, r2); codegen::gen_get_reg32(ctx.builder, r1); codegen::gen_call_fn2(ctx.builder, "cmp32") } pub fn instr16_50_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, AX); } pub fn instr32_50_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EAX); } pub fn instr16_51_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, CX); } pub fn instr32_51_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, ECX); } pub fn instr16_52_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, DX); } pub fn instr32_52_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EDX); } pub fn instr16_53_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, BX); } pub fn instr32_53_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EBX); } pub fn instr16_54_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, SP); } pub fn instr32_54_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, ESP); } pub fn instr16_55_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, BP); } pub fn instr32_55_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EBP); } pub fn instr16_56_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, SI); } pub fn instr32_56_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, ESI); } pub fn instr16_57_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, DI); } pub fn instr32_57_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EDI); } pub fn instr16_58_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, AX); } pub fn instr32_58_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, EAX); } pub fn instr16_59_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, CX); } pub fn instr32_59_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, ECX); } pub fn instr16_5A_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, DX); } pub fn instr32_5A_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, EDX); } pub fn instr16_5B_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, BX); } pub fn instr32_5B_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, EBX); } // hole for pop esp pub fn instr16_5D_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, BP); } pub fn instr32_5D_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, EBP); } pub fn instr16_5E_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, SI); } pub fn instr32_5E_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, ESI); } pub fn instr16_5F_jit(ctx: &mut JitContext) { pop16_reg_jit(ctx, DI); } pub fn instr32_5F_jit(ctx: &mut JitContext) { pop32_reg_jit(ctx, EDI); } pub fn instr16_68_jit(ctx: &mut JitContext, imm16: u32) { push16_imm_jit(ctx, imm16) } pub fn instr32_68_jit(ctx: &mut JitContext, imm32: u32) { push32_imm_jit(ctx, imm32) } pub fn instr16_6A_jit(ctx: &mut JitContext, imm16: u32) { push16_imm_jit(ctx, imm16) } pub fn instr32_6A_jit(ctx: &mut JitContext, imm32: u32) { push32_imm_jit(ctx, imm32) } // Code for conditional jumps is generated automatically by the basic block codegen pub fn instr16_70_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_70_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_71_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_71_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_72_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_72_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_73_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_73_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_74_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_74_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_75_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_75_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_76_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_76_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_77_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_77_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_78_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_78_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_79_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_79_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7A_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7A_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7B_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7B_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7C_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7C_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7D_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7D_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7E_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7E_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_7F_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_7F_jit(_ctx: &mut JitContext, _imm: u32) {} define_instruction_read8!("test8", instr_84_mem_jit, instr_84_reg_jit); define_instruction_read16!("test16", instr16_85_mem_jit, instr16_85_reg_jit); define_instruction_read32!("test32", instr32_85_mem_jit, instr32_85_reg_jit); pub fn instr_88_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); ctx.builder .instruction_body .const_i32(global_pointers::get_reg8_offset(r) as i32); ctx.builder.instruction_body.load_u8_from_stack(0); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write8(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); } pub fn instr_88_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg8_r(ctx, r1, r2); } pub fn instr16_89_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); codegen::gen_get_reg16(ctx.builder, r); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write16(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); } pub fn instr16_89_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg16_r(ctx, r1, r2); } pub fn instr32_89_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { // Pseudo: safe_write32(modrm_resolve(modrm_byte), reg32s[r]); codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r) as i32); ctx.builder.instruction_body.load_aligned_i32_from_stack(0); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write32(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); } pub fn instr32_89_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg32_r(ctx, r1, r2); } pub fn instr_8A_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { // Pseudo: reg8[r] = safe_read8(modrm_resolve(modrm_byte)); ctx.builder .instruction_body .const_i32(global_pointers::get_reg8_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); ctx.builder.instruction_body.store_u8(0); } pub fn instr_8A_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg8_r(ctx, r2, r1); } pub fn instr16_8B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { // Pseudo: reg16[r] = safe_read16(modrm_resolve(modrm_byte)); ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read16(ctx); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn instr16_8B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg16_r(ctx, r2, r1); } pub fn instr32_8B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { // Pseudo: reg32s[r] = safe_read32s(modrm_resolve(modrm_byte)); ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read32(ctx); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr32_8B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_set_reg32_r(ctx, r2, r1); } pub fn instr16_8D_mem_jit(ctx: &mut JitContext, modrm_byte: u8, reg: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(reg) as i32); ctx.cpu.prefixes |= SEG_PREFIX_ZERO; codegen::gen_modrm_resolve(ctx, modrm_byte); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn instr32_8D_mem_jit(ctx: &mut JitContext, modrm_byte: u8, reg: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(reg) as i32); ctx.cpu.prefixes |= SEG_PREFIX_ZERO; codegen::gen_modrm_resolve(ctx, modrm_byte); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr16_8D_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_fn2_const(ctx, "instr16_8D_reg", r1, r2); } pub fn instr32_8D_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { codegen::gen_fn2_const(ctx, "instr32_8D_reg", r1, r2); } pub fn instr16_8F_0_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(regs::SP) as i32); codegen::gen_get_reg16(ctx.builder, regs::SP); ctx.builder.instruction_body.const_i32(2); ctx.builder.instruction_body.add_i32(); ctx.builder.instruction_body.store_aligned_u16(0); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_modrm_fn0(ctx, "instr16_8F_0_mem_jit"); } pub fn instr16_8F_0_reg_jit(ctx: &mut JitContext, r: u32) { codegen::gen_fn1_const(ctx, "instr16_8F_0_reg", r); } pub fn instr32_8F_0_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(regs::ESP) as i32); codegen::gen_get_reg32(ctx.builder, regs::ESP); ctx.builder.instruction_body.const_i32(4); ctx.builder.instruction_body.add_i32(); ctx.builder.instruction_body.store_aligned_i32(0); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_modrm_fn0(ctx, "instr32_8F_0_mem_jit"); } pub fn instr32_8F_0_reg_jit(ctx: &mut JitContext, r: u32) { codegen::gen_fn1_const(ctx, "instr32_8F_0_reg", r); } pub fn instr16_E8_jit(ctx: &mut JitContext, imm: u32) { codegen::gen_get_real_eip(ctx); let value_local = ctx.builder.set_new_local(); codegen::gen_push16(ctx, &value_local); ctx.builder.free_local(value_local); codegen::gen_jmp_rel16(ctx, imm as u16); } pub fn instr32_E8_jit(ctx: &mut JitContext, imm: u32) { codegen::gen_get_real_eip(ctx); let value_local = ctx.builder.set_new_local(); codegen::gen_push32(ctx, &value_local); ctx.builder.free_local(value_local); ctx.builder .instruction_body .const_i32(global_pointers::INSTRUCTION_POINTER as i32); ctx.builder .instruction_body .load_aligned_i32(global_pointers::INSTRUCTION_POINTER); ctx.builder.instruction_body.const_i32(imm as i32); ctx.builder.instruction_body.add_i32(); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr16_E9_jit(ctx: &mut JitContext, imm: u32) { codegen::gen_jmp_rel16(ctx, imm as u16); } pub fn instr32_E9_jit(ctx: &mut JitContext, imm: u32) { codegen::gen_relative_jump(ctx.builder, imm as i32); } pub fn instr16_C3_jit(ctx: &mut JitContext) { let cs_addr = global_pointers::get_seg_offset(CS); ctx.builder .instruction_body .const_i32(global_pointers::INSTRUCTION_POINTER as i32); ctx.builder.instruction_body.load_aligned_i32(cs_addr); codegen::gen_pop16(ctx); ctx.builder.instruction_body.add_i32(); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr32_C3_jit(ctx: &mut JitContext) { ctx.builder .instruction_body .const_i32(global_pointers::INSTRUCTION_POINTER as i32); // cs = segment_offsets[CS] ctx.builder .instruction_body .load_aligned_i32(global_pointers::get_seg_offset(CS)); // ip = pop32s() codegen::gen_pop32s(ctx); // cs + ip ctx.builder.instruction_body.add_i32(); // dbg_assert(is_asize_32() || ip < 0x10000); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr16_EB_jit(ctx: &mut JitContext, imm8: u32) { codegen::gen_jmp_rel16(ctx, imm8 as u16); // dbg_assert(is_asize_32() || get_real_eip() < 0x10000); } pub fn instr32_EB_jit(ctx: &mut JitContext, imm8: u32) { // jmp near codegen::gen_relative_jump(ctx.builder, imm8 as i32); // dbg_assert(is_asize_32() || get_real_eip() < 0x10000); } pub fn instr16_FF_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { push16_mem_jit(ctx, modrm_byte) } pub fn instr16_FF_6_reg_jit(ctx: &mut JitContext, r: u32) { push16_reg_jit(ctx, r) } pub fn instr32_FF_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { push32_mem_jit(ctx, modrm_byte) } pub fn instr32_FF_6_reg_jit(ctx: &mut JitContext, r: u32) { push32_reg_jit(ctx, r) } // Code for conditional jumps is generated automatically by the basic block codegen pub fn instr16_0F80_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F81_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F82_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F83_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F84_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F85_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F86_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F87_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F88_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F89_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8A_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8B_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8C_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8D_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8E_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr16_0F8F_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F80_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F81_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F82_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F83_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F84_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F85_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F86_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F87_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F88_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F89_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8A_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8B_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8C_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8D_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8E_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr32_0F8F_jit(_ctx: &mut JitContext, _imm: u32) {} pub fn instr_90_jit(_ctx: &mut JitContext) {} pub fn instr_0F19_mem_jit(ctx: &mut JitContext, modrm_byte: u8, _reg: u32) { modrm::skip(ctx.cpu, modrm_byte); } pub fn instr_0F19_reg_jit(_ctx: &mut JitContext, _r1: u32, _r2: u32) {} pub fn instr_0F1C_mem_jit(ctx: &mut JitContext, modrm_byte: u8, _reg: u32) { modrm::skip(ctx.cpu, modrm_byte); } pub fn instr_0F1C_reg_jit(_ctx: &mut JitContext, _r1: u32, _r2: u32) {} pub fn instr_0F1D_mem_jit(ctx: &mut JitContext, modrm_byte: u8, _reg: u32) { modrm::skip(ctx.cpu, modrm_byte); } pub fn instr_0F1D_reg_jit(_ctx: &mut JitContext, _r1: u32, _r2: u32) {} pub fn instr_0F1E_mem_jit(ctx: &mut JitContext, modrm_byte: u8, _reg: u32) { modrm::skip(ctx.cpu, modrm_byte); } pub fn instr_0F1E_reg_jit(_ctx: &mut JitContext, _r1: u32, _r2: u32) {} pub fn instr_0F1F_mem_jit(ctx: &mut JitContext, modrm_byte: u8, _reg: u32) { modrm::skip(ctx.cpu, modrm_byte); } pub fn instr_0F1F_reg_jit(_ctx: &mut JitContext, _r1: u32, _r2: u32) {} pub fn instr16_0FB6_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { let builder = &mut ctx.builder; builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r2) as i32); codegen::gen_get_reg8(builder, r1); builder.instruction_body.store_aligned_u16(0); } pub fn instr16_0FB6_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn instr32_0FB6_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { let builder = &mut ctx.builder; builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r2) as i32); codegen::gen_get_reg8(builder, r1); builder.instruction_body.store_aligned_i32(0); } pub fn instr32_0FB6_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr16_0FBE_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { let builder = &mut ctx.builder; builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r2) as i32); codegen::gen_get_reg8(builder, r1); codegen::sign_extend_i8(builder); builder.instruction_body.store_aligned_u16(0); } pub fn instr16_0FBE_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); codegen::sign_extend_i8(ctx.builder); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn instr32_0FBE_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { let builder = &mut ctx.builder; builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r2) as i32); codegen::gen_get_reg8(builder, r1); codegen::sign_extend_i8(builder); builder.instruction_body.store_aligned_i32(0); } pub fn instr32_0FBE_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) { ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r) as i32); codegen::gen_modrm_resolve(ctx, modrm_byte); codegen::gen_safe_read8(ctx); codegen::sign_extend_i8(ctx.builder); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr_C6_0_reg_jit(ctx: &mut JitContext, r: u32, imm: u32) { // reg8[r] = imm; ctx.builder .instruction_body .const_i32(global_pointers::get_reg8_offset(r) as i32); ctx.builder.instruction_body.const_i32(imm as i32); ctx.builder.instruction_body.store_u8(0); } pub fn instr_C6_0_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); let imm = ctx.cpu.read_imm8(); ctx.builder.instruction_body.const_i32(imm as i32); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write8(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); } pub fn instr16_C7_0_reg_jit(ctx: &mut JitContext, r: u32, imm: u32) { // reg16[r] = imm; ctx.builder .instruction_body .const_i32(global_pointers::get_reg16_offset(r) as i32); ctx.builder.instruction_body.const_i32(imm as i32); ctx.builder.instruction_body.store_aligned_u16(0); } pub fn instr16_C7_0_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); let imm = ctx.cpu.read_imm16(); ctx.builder.instruction_body.const_i32(imm as i32); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write16(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); } pub fn instr32_C7_0_reg_jit(ctx: &mut JitContext, r: u32, imm: u32) { // reg32s[r] = imm; ctx.builder .instruction_body .const_i32(global_pointers::get_reg32_offset(r) as i32); ctx.builder.instruction_body.const_i32(imm as i32); ctx.builder.instruction_body.store_aligned_i32(0); } pub fn instr32_C7_0_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { codegen::gen_modrm_resolve(ctx, modrm_byte); let address_local = ctx.builder.set_new_local(); let imm = ctx.cpu.read_imm32(); ctx.builder.instruction_body.const_i32(imm as i32); let value_local = ctx.builder.set_new_local(); codegen::gen_safe_write32(ctx, &address_local, &value_local); ctx.builder.free_local(address_local); ctx.builder.free_local(value_local); }