/* handle the control word, setting FPROUND and detecting any
emulation warnings. */
pair = amd64g_check_fldcw ( (ULong)fpucw );
- fpround = (UInt)pair;
+ fpround = (UInt)pair & 0xFFFFFFFFULL;
ew = (VexEmWarn)(pair >> 32);
vex_state->guest_FPROUND = fpround & 3;
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;
+ return do_put_x87( False, (UChar*)x87_state, vex_state );
}
}
+/* This is used to implement 'fnsave'.
+ Writes 108 bytes at x87_state[0 .. 107]. */
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+void amd64g_dirtyhelper_FNSAVE ( /*IN*/VexGuestAMD64State* vex_state,
+ /*OUT*/HWord x87_state)
+{
+ do_get_x87( vex_state, (UChar*)x87_state );
+}
+
+
+/* This is used to implement 'fnsaves'.
+ Writes 94 bytes at x87_state[0 .. 93]. */
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+void amd64g_dirtyhelper_FNSAVES ( /*IN*/VexGuestAMD64State* vex_state,
+ /*OUT*/HWord x87_state)
+{
+ Int i, stno, preg;
+ UInt tagw;
+ ULong* vexRegs = (ULong*)(&vex_state->guest_FPREG[0]);
+ UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
+ Fpu_State_16* x87 = (Fpu_State_16*)x87_state;
+ UInt ftop = vex_state->guest_FTOP;
+ UInt c3210 = vex_state->guest_FC3210;
+
+ for (i = 0; i < 7; i++)
+ x87->env[i] = 0;
+
+ x87->env[FPS_ENV_STAT]
+ = toUShort(((ftop & 7) << 11) | (c3210 & 0x4700));
+ x87->env[FPS_ENV_CTRL]
+ = toUShort(amd64g_create_fpucw( vex_state->guest_FPROUND ));
+
+ /* Dump the register stack in ST order. */
+ tagw = 0;
+ for (stno = 0; stno < 8; stno++) {
+ preg = (stno + ftop) & 7;
+ if (vexTags[preg] == 0) {
+ /* register is empty */
+ tagw |= (3 << (2*preg));
+ convert_f64le_to_f80le( (UChar*)&vexRegs[preg],
+ &x87->reg[10*stno] );
+ } else {
+ /* register is full. */
+ tagw |= (0 << (2*preg));
+ convert_f64le_to_f80le( (UChar*)&vexRegs[preg],
+ &x87->reg[10*stno] );
+ }
+ }
+ x87->env[FPS_ENV_TAG] = toUShort(tagw);
+}
+
+
+/* This is used to implement 'frstor'.
+ Reads 108 bytes at x87_state[0 .. 107]. */
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+VexEmWarn amd64g_dirtyhelper_FRSTOR ( /*OUT*/VexGuestAMD64State* vex_state,
+ /*IN*/HWord x87_state)
+{
+ return do_put_x87( True, (UChar*)x87_state, vex_state );
+}
+
+
+/* This is used to implement 'frstors'.
+ Reads 94 bytes at x87_state[0 .. 93]. */
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER */
+VexEmWarn amd64g_dirtyhelper_FRSTORS ( /*OUT*/VexGuestAMD64State* vex_state,
+ /*IN*/HWord x87_state)
+{
+ Int stno, preg;
+ UInt tag;
+ ULong* vexRegs = (ULong*)(&vex_state->guest_FPREG[0]);
+ UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
+ Fpu_State_16* x87 = (Fpu_State_16*)x87_state;
+ UInt ftop = (x87->env[FPS_ENV_STAT] >> 11) & 7;
+ UInt tagw = x87->env[FPS_ENV_TAG];
+ UInt fpucw = x87->env[FPS_ENV_CTRL];
+ UInt c3210 = x87->env[FPS_ENV_STAT] & 0x4700;
+ VexEmWarn ew;
+ UInt fpround;
+ ULong pair;
+
+ /* Copy registers and tags */
+ for (stno = 0; stno < 8; stno++) {
+ preg = (stno + ftop) & 7;
+ tag = (tagw >> (2*preg)) & 3;
+ if (tag == 3) {
+ /* register is empty */
+ /* hmm, if it's empty, does it still get written? Probably
+ safer to say it does. If we don't, memcheck could get out
+ of sync, in that it thinks all FP registers are defined by
+ this helper, but in reality some have not been updated. */
+ vexRegs[preg] = 0; /* IEEE754 64-bit zero */
+ vexTags[preg] = 0;
+ } else {
+ /* register is non-empty */
+ convert_f80le_to_f64le( &x87->reg[10*stno],
+ (UChar*)&vexRegs[preg] );
+ 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 = (UInt)pair & 0xFFFFFFFFULL;
+ ew = (VexEmWarn)(pair >> 32);
+
+ vex_state->guest_FPROUND = fpround & 3;
+
+ /* emulation warnings --> caller */
+ return ew;
+}
+
+
/*---------------------------------------------------------------*/
/*--- Misc integer helpers, including rotates and CPUID. ---*/
/*---------------------------------------------------------------*/
fp_pop();
break;
-//.. case 4: { /* FRSTOR m108 */
-//.. /* Uses dirty helper:
-//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
-//.. IRTemp ew = newTemp(Ity_I32);
-//.. IRDirty* d = unsafeIRDirty_0_N (
-//.. 0/*regparms*/,
-//.. "x86g_dirtyhelper_FRSTOR",
-//.. &x86g_dirtyhelper_FRSTOR,
-//.. 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 = 108;
-//..
-//.. /* 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("frstor %s\n", dis_buf);
-//.. break;
-//.. }
-//..
-//.. case 6: { /* FNSAVE m108 */
-//.. /* Uses dirty helper:
-//.. void 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 = OFFB_FTOP;
-//.. d->fxState[0].size = sizeof(UInt);
-//..
-//.. d->fxState[1].fx = Ifx_Read;
-//.. d->fxState[1].offset = OFFB_FPREGS;
-//.. d->fxState[1].size = 8 * sizeof(ULong);
-//..
-//.. d->fxState[2].fx = Ifx_Read;
-//.. d->fxState[2].offset = OFFB_FPTAGS;
-//.. d->fxState[2].size = 8 * sizeof(UChar);
-//..
-//.. d->fxState[3].fx = Ifx_Read;
-//.. d->fxState[3].offset = OFFB_FPROUND;
-//.. d->fxState[3].size = sizeof(UInt);
-//..
-//.. d->fxState[4].fx = Ifx_Read;
-//.. d->fxState[4].offset = OFFB_FC3210;
-//.. d->fxState[4].size = sizeof(UInt);
-//..
-//.. stmt( IRStmt_Dirty(d) );
-//..
-//.. DIP("fnsave %s\n", dis_buf);
-//.. break;
-//.. }
+ case 4: { /* FRSTOR m94/m108 */
+ IRTemp ew = newTemp(Ity_I32);
+ IRTemp w64 = newTemp(Ity_I64);
+ IRDirty* d;
+ if ( have66(pfx) ) {
+ /* Uses dirty helper:
+ VexEmWarn amd64g_dirtyhelper_FRSTORS
+ ( VexGuestAMD64State*, HWord ) */
+ d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "amd64g_dirtyhelper_FRSTORS",
+ &amd64g_dirtyhelper_FRSTORS,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->mSize = 94;
+ } else {
+ /* Uses dirty helper:
+ VexEmWarn amd64g_dirtyhelper_FRSTOR
+ ( VexGuestAMD64State*, HWord ) */
+ d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "amd64g_dirtyhelper_FRSTOR",
+ &amd64g_dirtyhelper_FRSTOR,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->mSize = 108;
+ }
+
+ d->needsBBP = True;
+ d->tmp = w64;
+ /* declare we're reading memory */
+ d->mFx = Ifx_Read;
+ d->mAddr = mkexpr(addr);
+ /* d->mSize set above */
+
+ /* 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(ULong);
+
+ d->fxState[4].fx = Ifx_Write;
+ d->fxState[4].offset = OFFB_FC3210;
+ d->fxState[4].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 )
+ )
+ );
+
+ if ( have66(pfx) ) {
+ DIP("frstors %s\n", dis_buf);
+ } else {
+ DIP("frstor %s\n", dis_buf);
+ }
+ break;
+ }
+
+ case 6: { /* FNSAVE m94/m108 */
+ IRDirty *d;
+ if ( have66(pfx) ) {
+ /* Uses dirty helper:
+ void amd64g_dirtyhelper_FNSAVES ( VexGuestX86State*, HWord ) */
+ d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "amd64g_dirtyhelper_FNSAVES",
+ &amd64g_dirtyhelper_FNSAVES,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->mSize = 94;
+ } else {
+ /* Uses dirty helper:
+ void amd64g_dirtyhelper_FNSAVE ( VexGuestX86State*, HWord ) */
+ d = unsafeIRDirty_0_N (
+ 0/*regparms*/,
+ "amd64g_dirtyhelper_FNSAVE",
+ &amd64g_dirtyhelper_FNSAVE,
+ mkIRExprVec_1( mkexpr(addr) )
+ );
+ d->mSize = 108;
+ }
+ d->needsBBP = True;
+ /* declare we're writing memory */
+ d->mFx = Ifx_Write;
+ d->mAddr = mkexpr(addr);
+ /* d->mSize set above */
+
+ /* declare we're reading guest state */
+ d->nFxState = 5;
+
+ 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_FPREGS;
+ d->fxState[1].size = 8 * sizeof(ULong);
+
+ d->fxState[2].fx = Ifx_Read;
+ d->fxState[2].offset = OFFB_FPTAGS;
+ d->fxState[2].size = 8 * sizeof(UChar);
+
+ d->fxState[3].fx = Ifx_Read;
+ d->fxState[3].offset = OFFB_FPROUND;
+ d->fxState[3].size = sizeof(ULong);
+
+ d->fxState[4].fx = Ifx_Read;
+ d->fxState[4].offset = OFFB_FC3210;
+ d->fxState[4].size = sizeof(ULong);
+
+ stmt( IRStmt_Dirty(d) );
+
+ if ( have66(pfx) ) {
+ DIP("fnsaves %s\n", dis_buf);
+ } else {
+ DIP("fnsave %s\n", dis_buf);
+ }
+ break;
+ }
case 7: { /* FNSTSW m16 */
IRExpr* sw = get_FPU_sw();
if ( (opc == 0xD9 && getUChar(delta+0) == 0xFA)/*fsqrt*/ )
redundantREXWok = True;
- if ( (sz == 4 || (sz == 8 && redundantREXWok))
- && haveNo66noF2noF3(pfx)) {
- Bool decode_OK = False;
- delta = dis_FPU ( &decode_OK, vbi, pfx, delta );
- if (!decode_OK)
- goto decode_failure;
- } else {
+ Bool size_OK = False;
+ if ( sz == 4 )
+ size_OK = True;
+ else if ( sz == 8 )
+ size_OK = redundantREXWok;
+ else if ( sz == 2 ) {
+ int mod_rm = getUChar(delta+0);
+ int reg = gregLO3ofRM(mod_rm);
+ /* The HotSpot JVM uses these */
+ if ( (opc == 0xDD) && (reg == 0 /* FLDL */ ||
+ reg == 4 /* FNSAVE */ ||
+ reg == 6 /* FRSTOR */ ) )
+ size_OK = True;
+ }
+ /* AMD manual says 0x66 size override is ignored, except where
+ it is meaningful */
+ if (!size_OK)
goto decode_failure;
- }
+
+ Bool decode_OK = False;
+ delta = dis_FPU ( &decode_OK, vbi, pfx, delta );
+ if (!decode_OK)
+ goto decode_failure;
+
return delta;
}