]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 guest: Implement various insns:
authorJulian Seward <jseward@acm.org>
Mon, 6 Dec 2004 14:29:12 +0000 (14:29 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 6 Dec 2004 14:29:12 +0000 (14:29 +0000)
   ldmxcsr/stmxcsr
   fldenv/fstenv
   prefetch of various flavours (no-op for us)
   fclex (no-op for us)
   Some segment reg stuff, but nothing usable yet

git-svn-id: svn://svn.valgrind.org/vex/trunk@629

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/main/vex_main.c
VEX/priv/main/vex_util.c
VEX/pub/libvex_emwarn.h
VEX/pub/libvex_guest_x86.h

index 63141307c052e4ecb2820b4a0bff6c7c960f50b1..dd058f543f14b57ba0ae948ae2148a4e1851a649 100644 (file)
@@ -97,7 +97,11 @@ extern ULong x86g_calculate_RCR  (
 
 extern ULong x86h_check_fldcw ( UInt fpucw );
 
-extern UInt x86h_create_fpucw ( UInt fptrz );
+extern UInt x86h_create_fpucw ( UInt fpround );
+
+extern ULong x86h_check_ldmxcsr ( UInt mxcsr );
+
+extern UInt x86h_create_mxcsr ( UInt sseround );
 
 /* --- Clean helpers for MMX --- */
 
@@ -179,7 +183,13 @@ extern void  x86g_dirtyhelper_CPUID ( VexGuestX86State* );
 
 extern void  x86g_dirtyhelper_FSAVE ( VexGuestX86State*, HWord );
 
-extern void x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord );
+extern VexEmWarn
+            x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord );
+
+extern void x86g_dirtyhelper_FSTENV ( VexGuestX86State*, HWord );
+
+extern VexEmWarn 
+            x86g_dirtyhelper_FLDENV ( VexGuestX86State*, HWord );
 
 
 /*---------------------------------------------------------*/
index 056b30564d72b757bd95d87c6a008a3e567d2a45..34410f2a9bb6fe895d53650dbffaa6d824a5a462 100644 (file)
@@ -1387,11 +1387,11 @@ typedef
 #define FP_REG(ii)    (10*(7-(ii)))
 
 
+/* CLEAN HELPER */
 /* native_fpucw[15:0] contains a x87 native format FPU control word.
    Extract from it the required FPROUND value and any resulting
    emulation warning, and return (warn << 32) | fpround value. 
 */
-/* CLEAN HELPER */
 ULong x86h_check_fldcw ( UInt fpucw )
 {
    /* Decide on a rounding mode.  fpucw[11:10] holds it. */
@@ -1415,8 +1415,8 @@ ULong x86h_check_fldcw ( UInt fpucw )
 }
 
 /* CLEAN HELPER */
-/* Given fprtz as 1 or 0, create a suitable x87 native format
-   FPU control word. */
+/* Given fpround as an IRRoundingMode value, create a suitable x87
+   native format FPU control word. */
 UInt x86h_create_fpucw ( UInt fpround )
 {
    fpround &= 3;
@@ -1424,9 +1424,51 @@ UInt x86h_create_fpucw ( UInt fpround )
 }
 
 
-/* VISIBLE TO LIBVEX CLIENT */
-VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
-                                    /*OUT*/VexGuestX86State* vex_state )
+/* CLEAN HELPER */
+/* native_fpucw[15:0] contains a SSE native format MXCSR value.
+   Extract from it the required SSEROUND value and any resulting
+   emulation warning, and return (warn << 32) | sseround value.
+*/
+ULong x86h_check_ldmxcsr ( UInt mxcsr )
+{
+   /* Decide on a rounding mode.  mxcsr[14:13] holds it. */
+   /* NOTE, encoded exactly as per enum IRRoundingMode. */
+   UInt rmode = (mxcsr >> 13) & 3;
+
+   /* Detect any required emulation warnings. */
+   VexEmWarn ew = EmWarn_NONE;
+
+   if ((mxcsr & 0x1F80) != 0x1F80) {
+      /* unmasked exceptions! */
+      ew = EmWarn_X86_sseExns;
+   }
+   else 
+   if ((mxcsr & (1<<6)) || (mxcsr & (1<<15))) {
+      /* FZ or DAZ is set */
+      ew = EmWarn_X86_fz_daz;
+   }
+
+   return (((ULong)ew) << 32) | ((ULong)rmode);
+}
+
+
+/* CLEAN HELPER */
+/* Given sseround as an IRRoundingMode value, create a suitable SSE
+   native format MXCSR value. */
+UInt x86h_create_mxcsr ( UInt sseround )
+{
+   sseround &= 3;
+   return 0x1F80 | (sseround << 13);
+}
+
+
+/* This is used to implement both 'frstor' and 'fldenv'.  The latter
+   appears to differ from the former only in that the 8 FP registers
+   themselves are not transferred into the guest state. */
+static
+VexEmWarn put_x87 ( Bool moveRegs,
+                    /*IN*/UChar* x87_state,
+                    /*OUT*/VexGuestX86State* vex_state )
 {
    Int        r;
    UInt       tag;
@@ -1450,7 +1492,9 @@ VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
          vexTags[r] = 0;
       } else {
          /* register is non-empty */
-         convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] );
+         if (moveRegs)
+            convert_f80le_to_f64le( &x87->reg[FP_REG(r)], 
+                                    (UChar*)&vexRegs[r] );
          vexTags[r] = 1;
       }
    }
@@ -1474,6 +1518,14 @@ VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
 }
 
 
+/* VISIBLE TO LIBVEX CLIENT */
+VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
+                                    /*OUT*/VexGuestX86State* vex_state )
+{
+   return put_x87(True, x87_state, vex_state);
+}
+
+
 /* VISIBLE TO LIBVEX CLIENT */
 void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
                                /*OUT*/UChar* x87_state )
@@ -1503,7 +1555,7 @@ void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
       } else {
          /* register is full. */
          tagw |= (0 << (2*r));
-         convert_f64le_to_f80le( (UChar*)&vexRegs[r],  &x87->reg[FP_REG(r)] );
+         convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
       }
    }
    x87->env[FP_ENV_TAG] = tagw;
@@ -1693,9 +1745,29 @@ void x86g_dirtyhelper_FSAVE ( VexGuestX86State* gst, HWord addr )
 
 /* CALLED FROM GENERATED CODE */
 /* DIRTY HELPER (writes guest state, reads guest mem) */
-void x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr )
+VexEmWarn x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr )
+{
+   return LibVEX_GuestX86_put_x87( (UChar*)addr, gst );
+}
+
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (reads guest state, writes guest mem) */
+void x86g_dirtyhelper_FSTENV ( VexGuestX86State* gst, HWord addr )
+{
+   /* Somewhat roundabout, but at least it's simple. */
+   Int       i;
+   UShort*   addrP = (UShort*)addr;
+   Fpu_State tmp;
+   LibVEX_GuestX86_get_x87( gst, (UChar*)&tmp );
+   for (i = 0; i < 14; i++)
+      addrP[i] = tmp.env[i];
+}
+
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (writes guest state, reads guest mem) */
+VexEmWarn x86g_dirtyhelper_FLDENV ( VexGuestX86State* gst, HWord addr )
 {
-   LibVEX_GuestX86_put_x87( (UChar*)addr, gst );
+   return put_x87(False, (UChar*)addr, gst);
 }
 
 
index 69ca91c07af894d94a11e20c27fba64dda045c56..b5b18a5441f0b75fea10d835ccdcaa995ff9bf4c 100644 (file)
@@ -582,13 +582,11 @@ static IRExpr* getSReg ( UInt sreg )
    return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
 }
 
-#if 0
 static void putSReg ( UInt sreg, IRExpr* e )
 {
    vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
    stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
 }
-#endif
 
 static IRExpr* getXMMReg ( UInt xmmreg )
 {
@@ -1574,39 +1572,43 @@ UChar* sorbTxt ( UChar sorb )
       case 0x26: return "%es:";
       case 0x64: return "%fs:";
       case 0x65: return "%gs:";
-      default: vpanic("sorbTxt(x86)");
+      default: vpanic("sorbTxt(x86,guest)");
    }
 }
 
 
-/* Tmp is a TempReg holding a virtual address.  Convert it to a linear
-   address by adding any required segment override as indicated by
-   sorb. */
+/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
+   linear address by adding any required segment override as indicated
+   by sorb. */
 static
 IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
 {
-   //Int sreg, tsreg;
+  //IRTemp tsreg; //Int sreg, tsreg;
 
    if (sorb == 0)
       /* the common case - no override */
       return virtual;
 
-   unimplemented("segment overrides in new x86->IR phase");
+   unimplemented("vex x86->IR: segment override prefix");
 #if 0
    switch (sorb) {
       case 0x3E: sreg = R_DS; break;
       case 0x26: sreg = R_ES; break;
       case 0x64: sreg = R_FS; break;
       case 0x65: sreg = R_GS; break;
-      default: VG_(core_panic)("handleSegOverride");
+      default: vpanic("handleSegOverride(x86,guest)");
    }
 
-   tsreg = newTemp(cb);
+   tsreg = newTemp(Ity_I32);
+
+   /* tsreg becomes the relevant LDT descriptor */
+   assign( tsreg, unop(Iop_16Uto32, getSReg(sreg)) );
+
+   /* virtual += segment_base(ldt[tsreg]); also do limit check */
+return 
+  binop(Iop_Add32, mkexpr(virtual),
 
-   /* sreg -> tsreg */
-   uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
 
-   /* tmp += segment_base(ldt[tsreg]); also do limit check */
    uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
 #endif
 }
@@ -1996,7 +1998,6 @@ UInt dis_op2_E_G ( UChar       sorb,
       assign( src,  getIReg(size,eregOfRM(rm)) );
 
       if (addSubCarry && op8 == Iop_Add8) {
-         vassert(0);
          helper_ADC( size, dst1, dst0, src );
          putIReg(size, gregOfRM(rm), mkexpr(dst1));
       } else
@@ -3927,6 +3928,65 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                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", dis_buf);
+               break;
+            }
+
             case 5: {/* FLDCW */
                /* The only thing we observe in the control word is the
                   rounding mode.  Therefore, pass the 16-bit value
@@ -3967,6 +4027,46 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                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", 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
@@ -4395,6 +4495,10 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                                     get_ST(0), get_ST(r_src)) );
                break;
 
+            case 0xE2:
+               DIP("fnclex\n");
+               break;
+
             case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
                fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
                break;
@@ -6128,34 +6232,33 @@ UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
 //--                        LDw (tmpa), tmpb
 //--                        PUTSEG tmpb, %Sw
 //-- */
-//-- static
-//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb, 
-//--                      UChar       sorb,
-//--                      Addr        eip0 )
-//-- {
-//--    UChar rm  = getUChar(eip0);
-//--    HChar dis_buf[50];
-//-- 
-//--    if (epartIsReg(rm)) {
-//--       Int tmpv = newTemp(cb);
-//--       uInstr2(cb, GET,    2, ArchReg, eregOfRM(rm), TempReg, tmpv);
-//--       uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
-//--       DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
-//--       return 1+eip0;
-//--    }
-//-- 
-//--    /* E refers to memory */    
-//--    {
-//--       UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
-//--       Int  tmpa = LOW24(pair);
-//--       Int  tmpb = newTemp(cb);
-//--       uInstr2(cb, LOAD,   2, TempReg, tmpa, TempReg, tmpb);
-//--       uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
-//--       DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
-//--       return HI8(pair)+eip0;
-//--    }
-//-- }
-//-- 
+static
+UInt dis_mov_Ew_Sw ( UChar sorb, UInt delta0 )
+{
+   UChar rm  = getIByte(delta0);
+   //HChar dis_buf[50];
+
+   if (epartIsReg(rm)) {
+      putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
+      DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
+      return 1+delta0;
+   }
+
+   /* E refers to memory */    
+   {
+     vassert(0);
+     /*
+      UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
+      Int  tmpa = LOW24(pair);
+      Int  tmpb = newTemp(cb);
+      uInstr2(cb, LOAD,   2, TempReg, tmpa, TempReg, tmpb);
+      uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
+      DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
+      return HI8(pair)+eip0;
+     */
+   }
+}
+
 //-- 
 //-- /* Moves of a segment register to Ew.
 //--       mov Sw, Ew  meaning
@@ -7459,7 +7562,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       }
 
       if (r2zero) {
-         assign(rmode, mkU32((UInt)Irrm_ZERO) );
+         assign( rmode, mkU32((UInt)Irrm_ZERO) );
       } else {
          assign( rmode, get_sse_roundingmode() );
       }
@@ -7487,6 +7590,53 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
+   if (insn[0] == 0x0F && insn[1] == 0xAE
+       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
+
+      IRTemp t64 = newTemp(Ity_I64);
+      IRTemp ew = newTemp(Ity_I32);
+
+      modrm = getIByte(delta+2);
+      vassert(!epartIsReg(modrm));
+      vassert(sz == 4);
+
+      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+      delta += 2+alen;
+      DIP("ldmxcsr %s", dis_buf);
+
+      /* The only thing we observe in %mxcsr is the rounding mode.
+         Therefore, pass the 32-bit value (SSE native-format control
+         word) to a clean helper, getting back a 64-bit value, the
+         lower half of which is the SSEROUND value to store, and the
+         upper half of which is the emulation-warning token which may
+         be generated.  
+      */
+      /* ULong x86h_check_ldmxcsr ( UInt ); */
+      assign( t64, mkIRExprCCall(
+                      Ity_I64, 0/*regparms*/, 
+                      "x86h_check_ldmxcsr",
+                      &x86h_check_ldmxcsr, 
+                      mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
+                   )
+            );
+
+      //put_sseround( unop(Iop_64to32, mkexpr(t64)) );
+      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
+      put_emwarn( mkexpr(ew) );
+      /* Finally, if an emulation warning was reported, side-exit to
+         the next insn, reporting the warning, so that Valgrind's
+         dispatcher sees the warning. */
+      stmt( 
+         IRStmt_Exit(
+            binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
+            Ijk_EmWarn,
+            IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
+         )
+      );
+      goto decode_success;
+   }
+
    /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x5F) {
       vassert(sz == 4);
@@ -7957,6 +8107,33 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
+   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
+   /* 0F 18 /2 = PREFETCH1 */
+   /* 0F 18 /3 = PREFETCH2 */
+   if (insn[0] == 0x0F && insn[1] == 0x18
+       && !epartIsReg(insn[2]) 
+       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
+      HChar* hintstr = "??";
+
+      modrm = getIByte(delta+2);
+      vassert(!epartIsReg(modrm));
+
+      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+      delta += 2+alen;
+
+      switch (gregOfRM(modrm)) {
+         case 0: hintstr = "nta"; break;
+         case 1: hintstr = "t0"; break;
+         case 2: hintstr = "t1"; break;
+         case 3: hintstr = "t2"; break;
+         default: vassert(0);
+      }
+
+      DIP("prefetch%s %s\n", hintstr, dis_buf);
+      goto decode_success;
+   }
+
    /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
    /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
    if (insn[0] == 0x0F && insn[1] == 0xF6) {
@@ -8122,6 +8299,31 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* 0F AE /3 = STMXCSR m32 -- load %mxcsr */
+   if (insn[0] == 0x0F && insn[1] == 0xAE
+       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
+      modrm = getIByte(delta+2);
+      vassert(sz == 4);
+      vassert(!epartIsReg(modrm));
+
+      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+      delta += 2+alen;
+
+      /* Fake up a native SSE mxcsr word.  The only thing it depends
+         on is SSEROUND[1:0], so call a clean helper to cook it up. 
+      */
+      /* UInt x86h_create_mxcsr ( UInt sseround ) */
+      DIP("stmxcsr %s", dis_buf);
+      storeLE( mkexpr(addr), 
+               mkIRExprCCall(
+                  Ity_I32, 0/*regp*/,
+                  "x86h_create_mxcsr", &x86h_create_mxcsr, 
+                  mkIRExprVec_1( get_fpround() ) 
+               ) 
+             );
+      goto decode_success;
+   }
+
    /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x5C) {
       vassert(sz == 4);
@@ -9867,10 +10069,10 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       delta = dis_mov_Sw_Ew(sorb, sz, delta);
       break;
 
-//--    case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
-//--       eip = dis_mov_Ew_Sw(cb, sorb, eip);
-//--       break;
-//-- 
+   case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
+      delta = dis_mov_Ew_Sw(sorb, delta);
+      break;
    case 0xA0: /* MOV Ob,AL */
       sz = 1;
       /* Fall through ... */
index 4fb486092be7880c6d3976b02cbd412dc8f9b17c..fa3e732fee0114e711ceaf15e0121d0dc665d8e0 100644 (file)
@@ -456,6 +456,8 @@ HChar* LibVEX_EmWarn_string ( VexEmWarn ew )
         return "Selection of non-80-bit x87 FP precision";
      case EmWarn_X86_sseExns:
         return "Unmasking SSE FP exceptionss";
+     case EmWarn_X86_fz_daz:
+        return "Setting MXCSR.FZ or MXCSR.DAZ";
      default: 
         vpanic("LibVEX_EmWarn_string: unknown warning");
    }
index d45b11cf8ee19b64c254bfd71b09d7b0948f5d69..9fb32afc0e167acd18ea84573fe58ef7ec9f74ec 100644 (file)
@@ -124,7 +124,7 @@ void* LibVEX_Alloc ( Int nbytes )
 
 void LibVEX_ClearTemporary ( Bool verb )
 {
-   vassert(vex_initdone);
+   /* vassert(vex_initdone); */ /* causes infinite assert loops */
    temporary_bytes_allocd_TOT += (ULong)temporary_bytes_allocd;
    temporary_count_allocs_TOT += (ULong)temporary_count_allocs;
    if (verb) {
index 9b1c6ac0e7f67ff7ce6e6a325b9c7f09e0258d7a..0da0db0195dc805811c8c23b33e77fa1e420d64d 100644 (file)
@@ -67,6 +67,9 @@ typedef
       /* unmasking SSE FP exceptions is not supported */
       EmWarn_X86_sseExns,
       
+      /* setting mxcsr.fz or mxcsr.daz is not supported */
+      EmWarn_X86_fz_daz,
+      
       EmWarn_NUMBER
    }
    VexEmWarn;
index c80fafd3b12248c0ccbfc5b7cfd64237843e2468..22011945a037a51b5868c6c889b047e002f18402 100644 (file)
    FPROUND[1:0] is the FPU's notional rounding mode, encoded as per
    the IRRoundingMode type (see libvex_ir.h).  This just happens to be
    the Intel encoding.  Note carefully, the rounding mode is only
-   observed on float-to-int conversions, and not for float-to-float
-   operations.
+   observed on float-to-int conversions, and on float-to-float
+   rounding, but not for general float-to-float operations, which are
+   always rounded-to-nearest.
+
+   Loads/stores of the FPU control word are faked accordingly -- on
+   loads, everything except the rounding mode is ignored, and on
+   stores, you get a vanilla control world (0x037F) with the rounding
+   mode patched in.  Hence the only values you can get are 0x037F,
+   0x077F, 0x0B7F or 0x0F7F.  Vex will emit an emulation warning if
+   you try and load a control word which either (1) unmasks FP
+   exceptions, or (2) changes the default (80-bit) precision.
 
    FC3210 contains the C3, C2, C1 and C0 bits in the same place they
    are in the FPU's status word.  (bits 14, 10, 9, 8 respectively).
    All other bits should be zero.  The relevant mask to select just
    those bits is 0x4700.  To select C3, C2 and C0 only, the mask is
-   0x4500.  */
+   0x4500.  
+
+   SSEROUND[1:0] is the SSE unit's notional rounding mode, encoded as
+   per the IRRoundingMode type.  As with the FPU control word, the
+   rounding mode is the only part of %MXCSR that Vex observes.  On
+   storing %MXCSR, you will get a vanilla word (0x1F80) with the
+   rounding mode patched in.  Hence the only values you will get are
+   0x1F80, 0x3F80, 0x5F80 or 0x7F80.  Vex will emit an emulation
+   warning if you try and load a control word which either (1) unmasks
+   any exceptions, (2) sets FZ (flush-to-zero) to 1, or (3) sets DAZ
+   (denormals-are-zeroes) to 1. */
 
 typedef
    struct {