Patch for the bug https://bugs.launchpad.net/qemu/+bug/661696
The testcase: $ cat test.c #include <stdio.h> extern void *x; int main() { int a; asm volatile ("x: fldz\n\ push %%edx\n\ fnstenv -0xc(%%esp)\n\ pop %%edx\n" : "=d" (a) : : "memory"); printf ("%x %x\n", a, &x); return 0; } $ gcc -m32 test.c -o test $ ./test 80483ae 80483ae $ ./qemu-build/i386-linux-user/qemu-i386 ./test 0 80483ae $ ./qemu-fixed-build/i386-linux-user/qemu-i386 ./test 80483ae 80483ae The patch: Signed-off-by: Nikita A Skovoroda <chalk...@gmail.com> >From e07b99b12a9dd4d933936d5376efde8a992472dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BA=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D0=B4=D0=B0=20=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=D0=B8=D1=87?= <chalk...@gmail.com> Date: Fri, 26 Nov 2010 15:35:05 +0300 Subject: [PATCH] Fix FSTENV (and FSAVE) instructions in target-i386. Fixes bug #616696. --- target-i386/cpu.h | 1 + target-i386/helper.h | 2 ++ target-i386/op_helper.c | 9 +++++++-- target-i386/translate.c | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 06e40f3..aad0dcb 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -642,6 +642,7 @@ typedef struct CPUX86State { uint16_t fpuc; uint8_t fptags[8]; /* 0 = valid, 1 = empty */ FPReg fpregs[8]; + target_ulong fpip; /* emulator internal variables */ float_status fp_status; diff --git a/target-i386/helper.h b/target-i386/helper.h index 6b518ad..26b47a3 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -3,6 +3,8 @@ DEF_HELPER_FLAGS_1(cc_compute_all, TCG_CALL_PURE, i32, int) DEF_HELPER_FLAGS_1(cc_compute_c, TCG_CALL_PURE, i32, int) +DEF_HELPER_1(save_fpip, void, tl) + DEF_HELPER_0(lock, void) DEF_HELPER_0(unlock, void) DEF_HELPER_2(write_eflags, void, tl, i32) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 43fbd0c..ab65f0c 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -109,6 +109,11 @@ static const CPU86_LDouble f15rk[7] = static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; +void helper_save_fpip(target_ulong fpip) +{ + env->fpip = fpip; +} + void helper_lock(void) { spin_lock(&global_cpu_lock); @@ -4273,7 +4278,7 @@ void helper_fstenv(target_ulong ptr, int data32) stl(ptr, env->fpuc); stl(ptr + 4, fpus); stl(ptr + 8, fptag); - stl(ptr + 12, 0); /* fpip */ + stl(ptr + 12, env->fpip); /* fpip */ stl(ptr + 16, 0); /* fpcs */ stl(ptr + 20, 0); /* fpoo */ stl(ptr + 24, 0); /* fpos */ @@ -4282,7 +4287,7 @@ void helper_fstenv(target_ulong ptr, int data32) stw(ptr, env->fpuc); stw(ptr + 2, fpus); stw(ptr + 4, fptag); - stw(ptr + 6, 0); + stw(ptr + 6, env->fpip); stw(ptr + 8, 0); stw(ptr + 10, 0); stw(ptr + 12, 0); diff --git a/target-i386/translate.c b/target-i386/translate.c index 7b6e3c2..c7d1d33 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5974,6 +5974,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; } } + gen_helper_save_fpip(tcg_const_tl(pc_start - s->cs_base)); break; /************************/ /* string ops */ -- 1.7.3.2