Browse Source

fix push sreg only touches 16 bits of the stack dword

Fabian 1 year ago
parent
commit
651d0d83f9

+ 51 - 0
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);

+ 4 - 12
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() {

+ 3 - 7
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)))) {

+ 16 - 0
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<i32> {
     if *stack_size_32 { pop16_ss32() } else { pop16_ss16() }
 }

+ 6 - 36
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(