diff --git a/src/rust/codegen.rs b/src/rust/codegen.rs index fdd574a8..2c6a01e3 100644 --- a/src/rust/codegen.rs +++ b/src/rust/codegen.rs @@ -1529,6 +1529,57 @@ pub fn gen_push32(ctx: &mut JitContext, value_local: &WasmLocal) { ctx.builder.free_local(new_sp_local); } +pub fn gen_push32_sreg(ctx: &mut JitContext, reg: u32) { + gen_get_sreg(ctx, reg); + let value_local = ctx.builder.set_new_local(); + + if ctx.cpu.ssize_32() { + gen_get_reg32(ctx, regs::ESP); + } + else { + gen_get_reg16(ctx, regs::SP); + }; + + ctx.builder.const_i32(4); + ctx.builder.sub_i32(); + + let new_sp_local = if !ctx.cpu.ssize_32() || !ctx.cpu.has_flat_segmentation() { + let new_sp_local = ctx.builder.tee_new_local(); + if !ctx.cpu.ssize_32() { + ctx.builder.const_i32(0xFFFF); + ctx.builder.and_i32(); + } + + if !ctx.cpu.has_flat_segmentation() { + gen_get_ss_offset(ctx); + ctx.builder.add_i32(); + } + + let sp_local = ctx.builder.set_new_local(); + + gen_safe_write16(ctx, &sp_local, &value_local); + ctx.builder.free_local(sp_local); + + ctx.builder.get_local(&new_sp_local); + new_sp_local + } + else { + // short path: The address written to is equal to ESP/SP minus four + let new_sp_local = ctx.builder.tee_new_local(); + gen_safe_write16(ctx, &new_sp_local, &value_local); + new_sp_local + }; + + if ctx.cpu.ssize_32() { + gen_set_reg32(ctx, regs::ESP); + } + else { + gen_set_reg16(ctx, regs::SP); + }; + ctx.builder.free_local(new_sp_local); + ctx.builder.free_local(value_local); +} + pub fn gen_get_real_eip(ctx: &mut JitContext) { gen_get_eip(ctx.builder); ctx.builder.const_i32(!0xFFF); diff --git a/src/rust/cpu/instructions.rs b/src/rust/cpu/instructions.rs index 8d895888..57b5f937 100644 --- a/src/rust/cpu/instructions.rs +++ b/src/rust/cpu/instructions.rs @@ -58,9 +58,7 @@ pub unsafe fn instr32_05(imm32: i32) { write_reg32(EAX, add32(read_reg32(EAX), i pub unsafe fn instr16_06() { return_on_pagefault!(push16(*sreg.offset(ES as isize) as i32)); } -pub unsafe fn instr32_06() { - return_on_pagefault!(push32(*sreg.offset(ES as isize) as i32)); -} +pub unsafe fn instr32_06() { return_on_pagefault!(push32_sreg(ES)) } #[no_mangle] pub unsafe fn instr16_07() { @@ -123,9 +121,7 @@ pub unsafe fn instr32_0D(imm32: i32) { write_reg32(EAX, or32(read_reg32(EAX), im pub unsafe fn instr16_0E() { return_on_pagefault!(push16(*sreg.offset(CS as isize) as i32)); } -pub unsafe fn instr32_0E() { - return_on_pagefault!(push32(*sreg.offset(CS as isize) as i32)); -} +pub unsafe fn instr32_0E() { return_on_pagefault!(push32_sreg(CS)) } pub unsafe fn instr16_0F() { run_instruction0f_16(return_on_pagefault!(read_imm8())); } pub unsafe fn instr32_0F() { run_instruction0f_32(return_on_pagefault!(read_imm8())); } @@ -176,9 +172,7 @@ pub unsafe fn instr32_15(imm32: i32) { write_reg32(EAX, adc32(read_reg32(EAX), i pub unsafe fn instr16_16() { return_on_pagefault!(push16(*sreg.offset(SS as isize) as i32)); } -pub unsafe fn instr32_16() { - return_on_pagefault!(push32(*sreg.offset(SS as isize) as i32)); -} +pub unsafe fn instr32_16() { return_on_pagefault!(push32_sreg(SS)) } #[no_mangle] pub unsafe fn instr16_17() { @@ -244,9 +238,7 @@ pub unsafe fn instr32_1D(imm32: i32) { write_reg32(EAX, sbb32(read_reg32(EAX), i pub unsafe fn instr16_1E() { return_on_pagefault!(push16(*sreg.offset(DS as isize) as i32)); } -pub unsafe fn instr32_1E() { - return_on_pagefault!(push32(*sreg.offset(DS as isize) as i32)); -} +pub unsafe fn instr32_1E() { return_on_pagefault!(push32_sreg(DS)) } #[no_mangle] pub unsafe fn instr16_1F() { diff --git a/src/rust/cpu/instructions_0f.rs b/src/rust/cpu/instructions_0f.rs index 0ab397a5..3b1755e2 100644 --- a/src/rust/cpu/instructions_0f.rs +++ b/src/rust/cpu/instructions_0f.rs @@ -27,7 +27,7 @@ use cpu::fpu::fpu_set_tag_word; use cpu::global_pointers::*; use cpu::misc_instr::{ adjust_stack_reg, bswap, cmovcc16, cmovcc32, fxrstor, fxsave, get_stack_pointer, jmpcc16, - jmpcc32, push16, push32, setcc_mem, setcc_reg, test_b, test_be, test_l, test_le, test_o, + jmpcc32, push16, push32_sreg, setcc_mem, setcc_reg, test_b, test_be, test_l, test_le, test_o, test_p, test_s, test_z, }; use cpu::misc_instr::{lar, lsl, verr, verw}; @@ -3075,9 +3075,7 @@ pub unsafe fn instr_0F9F_mem(addr: i32, _: i32) { setcc_mem(!test_le(), addr); } pub unsafe fn instr16_0FA0() { return_on_pagefault!(push16(*sreg.offset(FS as isize) as i32)); } -pub unsafe fn instr32_0FA0() { - return_on_pagefault!(push32(*sreg.offset(FS as isize) as i32)); -} +pub unsafe fn instr32_0FA0() { return_on_pagefault!(push32_sreg(FS)) } #[no_mangle] pub unsafe fn instr16_0FA1() { if !switch_seg(FS, return_on_pagefault!(safe_read16(get_stack_pointer(0)))) { @@ -3296,9 +3294,7 @@ pub unsafe fn instr_0FA7() { undefined_instruction(); } pub unsafe fn instr16_0FA8() { return_on_pagefault!(push16(*sreg.offset(GS as isize) as i32)); } -pub unsafe fn instr32_0FA8() { - return_on_pagefault!(push32(*sreg.offset(GS as isize) as i32)); -} +pub unsafe fn instr32_0FA8() { return_on_pagefault!(push32_sreg(GS)) } #[no_mangle] pub unsafe fn instr16_0FA9() { if !switch_seg(GS, return_on_pagefault!(safe_read16(get_stack_pointer(0)))) { diff --git a/src/rust/cpu/misc_instr.rs b/src/rust/cpu/misc_instr.rs index 5cc3cbeb..09ad6c43 100644 --- a/src/rust/cpu/misc_instr.rs +++ b/src/rust/cpu/misc_instr.rs @@ -186,6 +186,22 @@ pub unsafe fn push32_ss32_mem(addr: i32) -> OrPageFault<()> { push32_ss32(safe_r pub unsafe fn push32(imm32: i32) -> OrPageFault<()> { if *stack_size_32 { push32_ss32(imm32) } else { push32_ss16(imm32) } } + +pub unsafe fn push32_sreg(i: i32) -> OrPageFault<()> { + // you can't make this up ... + if *stack_size_32 { + let new_esp = read_reg32(ESP) - 4; + safe_write16(get_seg_ss() + new_esp, *sreg.offset(i as isize) as i32)?; + write_reg32(ESP, new_esp); + } + else { + let new_sp = read_reg16(SP) - 4 & 0xFFFF; + safe_write16(get_seg_ss() + new_sp, *sreg.offset(i as isize) as i32)?; + write_reg16(SP, new_sp); + } + Ok(()) +} + pub unsafe fn pop16() -> OrPageFault { if *stack_size_32 { pop16_ss32() } else { pop16_ss16() } } diff --git a/src/rust/jit_instructions.rs b/src/rust/jit_instructions.rs index 56338eff..f6d2bca1 100644 --- a/src/rust/jit_instructions.rs +++ b/src/rust/jit_instructions.rs @@ -2507,12 +2507,7 @@ pub fn instr16_06_jit(ctx: &mut JitContext) { codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_06_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::ES); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_06_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::ES) } pub fn instr16_0E_jit(ctx: &mut JitContext) { codegen::gen_get_sreg(ctx, regs::CS); @@ -2520,12 +2515,7 @@ pub fn instr16_0E_jit(ctx: &mut JitContext) { codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_0E_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::CS); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_0E_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::CS) } pub fn instr16_16_jit(ctx: &mut JitContext) { codegen::gen_get_sreg(ctx, regs::SS); @@ -2533,12 +2523,7 @@ pub fn instr16_16_jit(ctx: &mut JitContext) { codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_16_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::SS); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_16_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::SS) } pub fn instr16_1E_jit(ctx: &mut JitContext) { codegen::gen_get_sreg(ctx, regs::DS); @@ -2546,12 +2531,7 @@ pub fn instr16_1E_jit(ctx: &mut JitContext) { codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_1E_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::DS); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_1E_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::DS) } pub fn instr16_40_jit(ctx: &mut JitContext) { gen_inc16_r(ctx, AX); } pub fn instr32_40_jit(ctx: &mut JitContext) { gen_inc32_r(ctx, EAX); } @@ -6858,24 +6838,14 @@ pub fn instr16_0FA0_jit(ctx: &mut JitContext) { codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_0FA0_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::FS); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_0FA0_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::FS) } pub fn instr16_0FA8_jit(ctx: &mut JitContext) { codegen::gen_get_sreg(ctx, regs::GS); let sreg = ctx.builder.set_new_local(); codegen::gen_push16(ctx, &sreg); ctx.builder.free_local(sreg); } -pub fn instr32_0FA8_jit(ctx: &mut JitContext) { - codegen::gen_get_sreg(ctx, regs::GS); - let sreg = ctx.builder.set_new_local(); - codegen::gen_push32(ctx, &sreg); - ctx.builder.free_local(sreg); -} +pub fn instr32_0FA8_jit(ctx: &mut JitContext) { codegen::gen_push32_sreg(ctx, regs::GS) } pub fn instr16_0FA3_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) { gen_bt(