]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement fldenv/fstenv on amd64.
authorJulian Seward <jseward@acm.org>
Mon, 13 Jun 2005 12:17:27 +0000 (12:17 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 13 Jun 2005 12:17:27 +0000 (12:17 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1206

VEX/priv/guest-amd64/gdefs.h
VEX/priv/guest-amd64/ghelpers.c
VEX/priv/guest-amd64/toIR.c
VEX/priv/guest-generic/g_generic_x87.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c

index 1cf7f6f1710295fe9691089bae228b195f3f49a3..6279014318c6beb27a0d88d14173cbdd285927ec 100644 (file)
@@ -105,6 +105,10 @@ extern ULong amd64g_check_ldmxcsr ( ULong mxcsr );
 
 extern ULong amd64g_create_mxcsr ( ULong sseround );
 
+extern VexEmWarn amd64g_dirtyhelper_FLDENV ( VexGuestAMD64State*, HWord );
+
+extern void amd64g_dirtyhelper_FSTENV ( VexGuestAMD64State*, HWord );
+
 /* Translate a guest virtual_addr into a guest linear address by
    consulting the supplied LDT/GDT structures.  Their representation
    must be as specified in pub/libvex_guest_amd64.h.  To indicate a
index 885d267d658476b1345256fa56e2cc0c69561380..1157e85cbe61cdd4100e7454b9ec4a6be016d889 100644 (file)
@@ -1308,6 +1308,98 @@ ULong amd64g_create_fpucw ( ULong fpround )
 }
 
 
+/* This is used to implement 'fldenv'.  
+   Reads 28 bytes at x87_state[0 .. 27]. */
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+VexEmWarn amd64g_dirtyhelper_FLDENV ( /*OUT*/VexGuestAMD64State* vex_state,
+                                      /*IN*/HWord x87_state)
+{
+   Int        stno, preg;
+   UInt       tag;
+   UChar*     vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
+   Fpu_State* x87     = (Fpu_State*)x87_state;
+   UInt       ftop    = (x87->env[FP_ENV_STAT] >> 11) & 7;
+   UInt       tagw    = x87->env[FP_ENV_TAG];
+   UInt       fpucw   = x87->env[FP_ENV_CTRL];
+   ULong      c3210   = x87->env[FP_ENV_STAT] & 0x4700;
+   VexEmWarn  ew;
+   ULong      fpround;
+   ULong      pair;
+
+   /* Copy tags */
+   for (stno = 0; stno < 8; stno++) {
+      preg = (stno + ftop) & 7;
+      tag = (tagw >> (2*preg)) & 3;
+      if (tag == 3) {
+         /* register is empty */
+         vexTags[preg] = 0;
+      } else {
+         /* register is non-empty */
+         vexTags[preg] = 1;
+      }
+   }
+
+   /* stack pointer */
+   vex_state->guest_FTOP = ftop;
+
+   /* status word */
+   vex_state->guest_FC3210 = c3210;
+
+   /* handle the control word, setting FPROUND and detecting any
+      emulation warnings. */
+   pair    = amd64g_check_fldcw ( (ULong)fpucw );
+   fpround = pair & 0xFFFFFFFFULL;
+   ew      = (VexEmWarn)(pair >> 32);
+   
+   vex_state->guest_FPROUND = fpround & 3;
+
+   /* emulation warnings --> caller */
+   return ew;
+}
+
+
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+/* Create an x87 FPU env from the guest state, as close as we can
+   approximate it.  Writes 28 bytes at x87_state[0..27]. */
+void amd64g_dirtyhelper_FSTENV ( /*IN*/VexGuestAMD64State* vex_state,
+                                 /*OUT*/HWord x87_state )
+{
+   Int        i, stno, preg;
+   UInt       tagw;
+   UChar*     vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
+   Fpu_State* x87     = (Fpu_State*)x87_state;
+   UInt       ftop    = vex_state->guest_FTOP;
+   ULong      c3210   = vex_state->guest_FC3210;
+
+   for (i = 0; i < 14; i++)
+      x87->env[i] = 0;
+
+   x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
+   x87->env[FP_ENV_STAT] 
+      = toUShort(((ftop & 7) << 11) | (c3210 & 0x4700));
+   x87->env[FP_ENV_CTRL] 
+      = toUShort(amd64g_create_fpucw( vex_state->guest_FPROUND ));
+
+   /* Compute the x87 tag word. */
+   tagw = 0;
+   for (stno = 0; stno < 8; stno++) {
+      preg = (stno + ftop) & 7;
+      if (vexTags[preg] == 0) {
+         /* register is empty */
+         tagw |= (3 << (2*preg));
+      } else {
+         /* register is full. */
+         tagw |= (0 << (2*preg));
+      }
+   }
+   x87->env[FP_ENV_TAG] = toUShort(tagw);
+
+   /* We don't dump the x87 registers, tho. */
+}
+
+
 /*---------------------------------------------------------------*/
 /*--- Misc integer helpers, including rotates and CPUID.      ---*/
 /*---------------------------------------------------------------*/
index ca4d5aa03af1268029cd1727b453e201983c88e2..c4d1815cca7cbb0f54eade6f8a684a19d1943286 100644 (file)
@@ -4596,64 +4596,62 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                fp_pop();
                break;
 
-//..             case 4: { /* FLDENV m108 */
-//..                /* Uses dirty helper: 
-//..                      VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */
-//..                IRTemp   ew = newTemp(Ity_I32);
-//..                IRDirty* d  = unsafeIRDirty_0_N ( 
-//..                                 0/*regparms*/, 
-//..                                 "x86g_dirtyhelper_FLDENV", 
-//..                                 &x86g_dirtyhelper_FLDENV,
-//..                                 mkIRExprVec_1( mkexpr(addr) )
-//..                              );
-//..                d->needsBBP = True;
-//..                d->tmp      = ew;
-//..                /* declare we're reading memory */
-//..                d->mFx   = Ifx_Read;
-//..                d->mAddr = mkexpr(addr);
-//..                d->mSize = 28;
-//.. 
-//..                /* declare we're writing guest state */
-//..                d->nFxState = 5;
-//.. 
-//..                d->fxState[0].fx     = Ifx_Write;
-//..                d->fxState[0].offset = OFFB_FTOP;
-//..                d->fxState[0].size   = sizeof(UInt);
-//.. 
-//..                d->fxState[1].fx     = Ifx_Write;
-//..                d->fxState[1].offset = OFFB_FPREGS;
-//..                d->fxState[1].size   = 8 * sizeof(ULong);
-//.. 
-//..                d->fxState[2].fx     = Ifx_Write;
-//..                d->fxState[2].offset = OFFB_FPTAGS;
-//..                d->fxState[2].size   = 8 * sizeof(UChar);
-//.. 
-//..                d->fxState[3].fx     = Ifx_Write;
-//..                d->fxState[3].offset = OFFB_FPROUND;
-//..                d->fxState[3].size   = sizeof(UInt);
-//.. 
-//..                d->fxState[4].fx     = Ifx_Write;
-//..                d->fxState[4].offset = OFFB_FC3210;
-//..                d->fxState[4].size   = sizeof(UInt);
-//.. 
-//..                stmt( IRStmt_Dirty(d) );
-//.. 
-//..                /* ew contains any emulation warning we may need to
-//..                   issue.  If needed, side-exit to the next insn,
-//..                   reporting the warning, so that Valgrind's dispatcher
-//..                   sees the warning. */
-//..                put_emwarn( mkexpr(ew) );
-//..                stmt( 
-//..                   IRStmt_Exit(
-//..                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
-//..                      Ijk_EmWarn,
-//..                      IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
-//..                   )
-//..                );
-//.. 
-//..                DIP("fldenv %s\n", dis_buf);
-//..                break;
-//..             }
+            case 4: { /* FLDENV m28 */
+               /* Uses dirty helper: 
+                     VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
+               IRTemp    ew = newTemp(Ity_I32);
+               IRTemp   w64 = newTemp(Ity_I64);
+               IRDirty*   d = unsafeIRDirty_0_N ( 
+                                 0/*regparms*/, 
+                                 "amd64g_dirtyhelper_FLDENV", 
+                                 &amd64g_dirtyhelper_FLDENV,
+                                 mkIRExprVec_1( mkexpr(addr) )
+                              );
+               d->needsBBP = True;
+               d->tmp      = w64;
+               /* declare we're reading memory */
+               d->mFx   = Ifx_Read;
+               d->mAddr = mkexpr(addr);
+               d->mSize = 28;
+
+               /* declare we're writing guest state */
+               d->nFxState = 4;
+
+               d->fxState[0].fx     = Ifx_Write;
+               d->fxState[0].offset = OFFB_FTOP;
+               d->fxState[0].size   = sizeof(UInt);
+
+               d->fxState[1].fx     = Ifx_Write;
+               d->fxState[1].offset = OFFB_FPTAGS;
+               d->fxState[1].size   = 8 * sizeof(UChar);
+
+               d->fxState[2].fx     = Ifx_Write;
+               d->fxState[2].offset = OFFB_FPROUND;
+               d->fxState[2].size   = sizeof(ULong);
+
+               d->fxState[3].fx     = Ifx_Write;
+               d->fxState[3].offset = OFFB_FC3210;
+               d->fxState[3].size   = sizeof(ULong);
+
+               stmt( IRStmt_Dirty(d) );
+
+               /* ew contains any emulation warning we may need to
+                  issue.  If needed, side-exit to the next insn,
+                  reporting the warning, so that Valgrind's dispatcher
+                  sees the warning. */
+              assign(ew, unop(Iop_64to32,mkexpr(w64)) );
+               put_emwarn( mkexpr(ew) );
+               stmt( 
+                  IRStmt_Exit(
+                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
+                     Ijk_EmWarn,
+                     IRConst_U64( guest_rip_bbstart+delta )
+                  )
+               );
+
+               DIP("fldenv %s\n", dis_buf);
+               break;
+            }
 
             case 5: {/* FLDCW */
                /* The only thing we observe in the control word is the
@@ -4695,51 +4693,51 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                break;
             }
 
-//..             case 6: { /* FNSTENV m28 */
-//..                /* Uses dirty helper: 
-//..                      void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
-//..                IRDirty* d = unsafeIRDirty_0_N ( 
-//..                                0/*regparms*/, 
-//..                                "x86g_dirtyhelper_FSTENV", 
-//..                                &x86g_dirtyhelper_FSTENV,
-//..                                mkIRExprVec_1( mkexpr(addr) )
-//..                             );
-//..                d->needsBBP = True;
-//..                /* declare we're writing memory */
-//..                d->mFx   = Ifx_Write;
-//..                d->mAddr = mkexpr(addr);
-//..                d->mSize = 28;
-//.. 
-//..                /* declare we're reading guest state */
-//..                d->nFxState = 4;
-//.. 
-//..                d->fxState[0].fx     = Ifx_Read;
-//..                d->fxState[0].offset = OFFB_FTOP;
-//..                d->fxState[0].size   = sizeof(UInt);
-//.. 
-//..                d->fxState[1].fx     = Ifx_Read;
-//..                d->fxState[1].offset = OFFB_FPTAGS;
-//..                d->fxState[1].size   = 8 * sizeof(UChar);
-//.. 
-//..                d->fxState[2].fx     = Ifx_Read;
-//..                d->fxState[2].offset = OFFB_FPROUND;
-//..                d->fxState[2].size   = sizeof(UInt);
-//.. 
-//..                d->fxState[3].fx     = Ifx_Read;
-//..                d->fxState[3].offset = OFFB_FC3210;
-//..                d->fxState[3].size   = sizeof(UInt);
-//.. 
-//..                stmt( IRStmt_Dirty(d) );
-//.. 
-//..                DIP("fnstenv %s\n", dis_buf);
-//..                break;
-//..             }
+            case 6: { /* FNSTENV m28 */
+               /* Uses dirty helper: 
+                     void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
+               IRDirty* d = unsafeIRDirty_0_N ( 
+                               0/*regparms*/, 
+                               "amd64g_dirtyhelper_FSTENV", 
+                               &amd64g_dirtyhelper_FSTENV,
+                               mkIRExprVec_1( mkexpr(addr) )
+                            );
+               d->needsBBP = True;
+               /* declare we're writing memory */
+               d->mFx   = Ifx_Write;
+               d->mAddr = mkexpr(addr);
+               d->mSize = 28;
+
+               /* declare we're reading guest state */
+               d->nFxState = 4;
+
+               d->fxState[0].fx     = Ifx_Read;
+               d->fxState[0].offset = OFFB_FTOP;
+               d->fxState[0].size   = sizeof(UInt);
+
+               d->fxState[1].fx     = Ifx_Read;
+               d->fxState[1].offset = OFFB_FPTAGS;
+               d->fxState[1].size   = 8 * sizeof(UChar);
+
+               d->fxState[2].fx     = Ifx_Read;
+               d->fxState[2].offset = OFFB_FPROUND;
+               d->fxState[2].size   = sizeof(ULong);
+
+               d->fxState[3].fx     = Ifx_Read;
+               d->fxState[3].offset = OFFB_FC3210;
+               d->fxState[3].size   = sizeof(ULong);
+
+               stmt( IRStmt_Dirty(d) );
+
+               DIP("fnstenv %s\n", dis_buf);
+               break;
+            }
 
             case 7: /* FNSTCW */
                /* Fake up a native x87 FPU control word.  The only
                   thing it depends on is FPROUND[1:0], so call a clean
                   helper to cook it up. */
-               /* ULong x86h_create_fpucw ( ULong fpround ) */
+               /* ULong amd64g_create_fpucw ( ULong fpround ) */
                DIP("fnstcw %s\n", dis_buf);
                storeLE(
                   mkexpr(addr), 
index 2901612955de5d434a102f1e74167e405e5f5b0f..50f0d69adf6697bd969abc75305f19cc69f5f9bd 100644 (file)
@@ -75,6 +75,26 @@ extern
 void convert_f80le_to_f64le ( /*IN*/UChar* f80, /*OUT*/UChar* f64 );
 
 
+/* Layout of the real x87 state. */
+typedef
+   struct {
+      UShort env[14];
+      UChar  reg[80];
+   }
+   Fpu_State;
+
+/* Offsets, in 16-bit ints, into the FPU environment (env) area. */
+#define FP_ENV_CTRL   0
+#define FP_ENV_STAT   2
+#define FP_ENV_TAG    4
+#define FP_ENV_IP     6 /* and 7 */
+#define FP_ENV_CS     8
+#define FP_ENV_OPOFF  10 /* and 11 */
+#define FP_ENV_OPSEL  12
+#define FP_REG(ii)    (10*(7-(ii)))
+
+
+
 #endif /* ndef __G_GENERIC_X87_H */
 
 /*---------------------------------------------------------------*/
index cd221c04695151eaee4cdb15a3cfb5f9619c4480..d3954590afc4436a1b4c7dc8c40aa0161d73c981 100644 (file)
@@ -1234,23 +1234,8 @@ void x86g_storeF80le ( UInt addrU, ULong f64 )
 /*----------------------------------------------*/
 
 /* Layout of the real x87 state. */
-
-typedef
-   struct {
-      UShort env[14];
-      UChar  reg[80];
-   }
-   Fpu_State;
-
-/* Offsets, in 16-bit ints, into the FPU environment (env) area. */
-#define FP_ENV_CTRL   0
-#define FP_ENV_STAT   2
-#define FP_ENV_TAG    4
-#define FP_ENV_IP     6 /* and 7 */
-#define FP_ENV_CS     8
-#define FP_ENV_OPOFF  10 /* and 11 */
-#define FP_ENV_OPSEL  12
-#define FP_REG(ii)    (10*(7-(ii)))
+/* 13 June 05: Fpu_State and auxiliary constants was moved to
+   g_generic_x87.h */
 
 
 /* CLEAN HELPER */
index cb0cfbe0e77f4d7b324fa2ba74c29f8ef95d2c90..9f2924ff18041b60a8154ddfd6f0c3011a527d4b 100644 (file)
@@ -3733,7 +3733,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
 
             case 4: { /* FLDENV m28 */
                /* Uses dirty helper: 
-                     VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */
+                     VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
                IRTemp   ew = newTemp(Ity_I32);
                IRDirty* d  = unsafeIRDirty_0_N ( 
                                 0/*regparms*/, 
@@ -3832,7 +3832,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
 
             case 6: { /* FNSTENV m28 */
                /* Uses dirty helper: 
-                     void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
+                     void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
                IRDirty* d = unsafeIRDirty_0_N ( 
                                0/*regparms*/, 
                                "x86g_dirtyhelper_FSTENV",