x86 guest: implement fsave/frstor instructions
git-svn-id: svn://svn.valgrind.org/vex/trunk@591 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-x86/gdefs.h b/priv/guest-x86/gdefs.h
index 77099c1..2cca503 100644
--- a/priv/guest-x86/gdefs.h
+++ b/priv/guest-x86/gdefs.h
@@ -160,6 +160,10 @@
extern void x86g_dirtyhelper_CPUID ( VexGuestX86State* );
+extern void x86g_dirtyhelper_FSAVE ( VexGuestX86State*, HWord );
+
+extern void x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord );
+
/*---------------------------------------------------------*/
/*--- Condition code stuff ---*/
diff --git a/priv/guest-x86/ghelpers.c b/priv/guest-x86/ghelpers.c
index af352b7..54a4259 100644
--- a/priv/guest-x86/ghelpers.c
+++ b/priv/guest-x86/ghelpers.c
@@ -1543,7 +1543,7 @@
/*----------------------------------------------*/
-/*--- Misc integer helpers ---*/
+/*--- Misc integer/fp helpers ---*/
/*----------------------------------------------*/
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
@@ -1620,6 +1620,20 @@
}
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (reads guest state, writes guest mem) */
+void x86g_dirtyhelper_FSAVE ( VexGuestX86State* gst, HWord addr )
+{
+ LibVEX_GuestX86_get_x87( gst, (UChar*)addr );
+}
+
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (writes guest state, reads guest mem) */
+void x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr )
+{
+ LibVEX_GuestX86_put_x87( (UChar*)addr, gst );
+}
+
/*----------------------------------------------*/
/*--- Helpers for MMX ---*/
diff --git a/priv/guest-x86/toIR.c b/priv/guest-x86/toIR.c
index ff33371..66646dd 100644
--- a/priv/guest-x86/toIR.c
+++ b/priv/guest-x86/toIR.c
@@ -4171,7 +4171,7 @@
}
case 7: { /* FSTP extended-real */
- /* Uses dirty helper: void storeF80le ( UInt, ULong ) */
+ /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
IRExpr** args
= mkIRExprVec_2( mkexpr(addr),
unop(Iop_ReinterpF64asI64, get_ST(0)) );
@@ -4366,6 +4366,92 @@
fp_pop();
break;
+ case 4: { /* FRSTOR m108 */
+ /* Uses dirty helper: x86g_do_FRSTOR ( VexGuestX86State*, UInt ) */
+ IRDirty* d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "x86g_dirtyhelper_FRSTOR",
+ &x86g_dirtyhelper_FRSTOR,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->needsBBP = True;
+ /* declare we're reading memory */
+ d->mFx = Ifx_Read;
+ d->mAddr = mkexpr(addr);
+ d->mSize = 108;
+
+ /* declare we're writing guest state */
+ d->nFxState = 5;
+
+ d->fxState[0].fx = Ifx_Write;
+ d->fxState[0].offset = offsetof(VexGuestX86State,guest_FTOP);
+ d->fxState[0].size = sizeof(UInt);
+
+ d->fxState[1].fx = Ifx_Write;
+ d->fxState[1].offset = offsetof(VexGuestX86State,guest_FPREG);
+ d->fxState[1].size = 8 * sizeof(ULong);
+
+ d->fxState[2].fx = Ifx_Write;
+ d->fxState[2].offset = offsetof(VexGuestX86State,guest_FPTAG);
+ d->fxState[2].size = 8 * sizeof(UChar);
+
+ d->fxState[3].fx = Ifx_Write;
+ d->fxState[3].offset = offsetof(VexGuestX86State,guest_FPUCW);
+ d->fxState[3].size = sizeof(UInt);
+
+ d->fxState[4].fx = Ifx_Write;
+ d->fxState[4].offset = offsetof(VexGuestX86State,guest_FC3210);
+ d->fxState[4].size = sizeof(UInt);
+
+ stmt( IRStmt_Dirty(d) );
+
+ DIP("frstor %s", dis_buf);
+ break;
+ }
+
+ case 6: { /* FNSAVE m108 */
+ /* Uses dirty helper: x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
+ IRDirty* d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "x86g_dirtyhelper_FSAVE",
+ &x86g_dirtyhelper_FSAVE,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->needsBBP = True;
+ /* declare we're writing memory */
+ d->mFx = Ifx_Write;
+ d->mAddr = mkexpr(addr);
+ d->mSize = 108;
+
+ /* declare we're reading guest state */
+ d->nFxState = 5;
+
+ d->fxState[0].fx = Ifx_Read;
+ d->fxState[0].offset = offsetof(VexGuestX86State,guest_FTOP);
+ d->fxState[0].size = sizeof(UInt);
+
+ d->fxState[1].fx = Ifx_Read;
+ d->fxState[1].offset = offsetof(VexGuestX86State,guest_FPREG);
+ d->fxState[1].size = 8 * sizeof(ULong);
+
+ d->fxState[2].fx = Ifx_Read;
+ d->fxState[2].offset = offsetof(VexGuestX86State,guest_FPTAG);
+ d->fxState[2].size = 8 * sizeof(UChar);
+
+ d->fxState[3].fx = Ifx_Read;
+ d->fxState[3].offset = offsetof(VexGuestX86State,guest_FPUCW);
+ d->fxState[3].size = sizeof(UInt);
+
+ d->fxState[4].fx = Ifx_Read;
+ d->fxState[4].offset = offsetof(VexGuestX86State,guest_FC3210);
+ d->fxState[4].size = sizeof(UInt);
+
+ stmt( IRStmt_Dirty(d) );
+
+ DIP("fnsave %s", dis_buf);
+ break;
+ }
+
default:
vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
vex_printf("first_opcode == 0xDD\n");
diff --git a/pub/libvex_ir.h b/pub/libvex_ir.h
index 9feb773..aa847a3 100644
--- a/pub/libvex_ir.h
+++ b/pub/libvex_ir.h
@@ -537,7 +537,7 @@
evaluation.
*/
-#define VEX_N_FXSTATE 4 /* enough for CPUID on x86 */
+#define VEX_N_FXSTATE 5 /* enough for FSAVE/FRSTOR on x86 */
typedef
enum {
diff --git a/test/frstor.c b/test/frstor.c
new file mode 100644
index 0000000..437f094
--- /dev/null
+++ b/test/frstor.c
@@ -0,0 +1,35 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void do_fsave ( void* p )
+{
+ asm("movl 8(%esp), %eax ; fsave (%eax)");
+}
+
+void do_frstor ( void* p )
+{
+ asm("movl 8(%esp), %eax ; frstor (%eax)");
+}
+
+int main ( void )
+{
+ int i;
+ unsigned short* buf = malloc(54*sizeof(int));
+ for (i = 0; i < 54; i++)
+ buf[i] = i;
+ buf[0] = 0x037f;
+
+ for (i = 0; i < 8; i++)
+ *(long double *)(&buf[14+5 *i]) = 0.1234 * i;
+
+ do_frstor(buf);
+ do_fsave(buf);
+ for (i = 0; i < 54; i++) {
+ printf("%04x ", buf[i]);
+ if (i > 0 && ((i % 12) == 11))
+ printf("\n");
+ }
+ printf("\n");
+ return 0;
+}
diff --git a/test/fsave.c b/test/fsave.c
new file mode 100644
index 0000000..2e0ba15
--- /dev/null
+++ b/test/fsave.c
@@ -0,0 +1,22 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void do_fsave ( void* p )
+{
+ asm("fldpi ; fld1; fldln2 ; movl 8(%esp), %eax ; fsave (%eax)");
+}
+
+int main ( void )
+{
+ int i;
+ unsigned int* buf = malloc(27*sizeof(int));
+ do_fsave(buf);
+ for (i = 0; i < 27; i++) {
+ printf("%08x ", buf[i]);
+ if (i > 0 && ((i % 6) == 5))
+ printf("\n");
+ }
+ printf("\n");
+ return 0;
+}