|
From: <sv...@va...> - 2011-02-14 13:33:45
|
Author: sewardj
Date: 2011-02-14 13:33:36 +0000 (Mon, 14 Feb 2011)
New Revision: 2094
Log:
Merge from trunk, r2078 (Add support for AAD and AAM (base 10 only).)
Modified:
branches/VEX_3_6_BRANCH/priv/guest_x86_defs.h
branches/VEX_3_6_BRANCH/priv/guest_x86_helpers.c
branches/VEX_3_6_BRANCH/priv/guest_x86_toIR.c
Modified: branches/VEX_3_6_BRANCH/priv/guest_x86_defs.h
===================================================================
--- branches/VEX_3_6_BRANCH/priv/guest_x86_defs.h 2011-02-14 13:30:26 UTC (rev 2093)
+++ branches/VEX_3_6_BRANCH/priv/guest_x86_defs.h 2011-02-14 13:33:36 UTC (rev 2094)
@@ -108,6 +108,8 @@
extern UInt x86g_calculate_daa_das_aaa_aas ( UInt AX_and_flags, UInt opcode );
+extern UInt x86g_calculate_aad_aam ( UInt AX_and_flags, UInt opcode );
+
extern ULong x86g_check_fldcw ( UInt fpucw );
extern UInt x86g_create_fpucw ( UInt fpround );
Modified: branches/VEX_3_6_BRANCH/priv/guest_x86_helpers.c
===================================================================
--- branches/VEX_3_6_BRANCH/priv/guest_x86_helpers.c 2011-02-14 13:30:26 UTC (rev 2093)
+++ branches/VEX_3_6_BRANCH/priv/guest_x86_helpers.c 2011-02-14 13:33:36 UTC (rev 2094)
@@ -2109,7 +2109,52 @@
return result;
}
+UInt x86g_calculate_aad_aam ( UInt flags_and_AX, UInt opcode )
+{
+ UInt r_AL = (flags_and_AX >> 0) & 0xFF;
+ UInt r_AH = (flags_and_AX >> 8) & 0xFF;
+ UInt r_O = (flags_and_AX >> (16 + X86G_CC_SHIFT_O)) & 1;
+ UInt r_S = (flags_and_AX >> (16 + X86G_CC_SHIFT_S)) & 1;
+ UInt r_Z = (flags_and_AX >> (16 + X86G_CC_SHIFT_Z)) & 1;
+ UInt r_A = (flags_and_AX >> (16 + X86G_CC_SHIFT_A)) & 1;
+ UInt r_C = (flags_and_AX >> (16 + X86G_CC_SHIFT_C)) & 1;
+ UInt r_P = (flags_and_AX >> (16 + X86G_CC_SHIFT_P)) & 1;
+ UInt result = 0;
+ switch (opcode) {
+ case 0xD4: { /* AAM */
+ r_AH = r_AL / 10;
+ r_AL = r_AL % 10;
+ break;
+ }
+ case 0xD5: { /* AAD */
+ r_AL = ((r_AH * 10) + r_AL) & 0xff;
+ r_AH = 0;
+ break;
+ }
+ default:
+ vassert(0);
+ }
+
+ r_O = 0; /* let's say (undefined) */
+ r_C = 0; /* let's say (undefined) */
+ r_A = 0; /* let's say (undefined) */
+ r_S = (r_AL & 0x80) ? 1 : 0;
+ r_Z = (r_AL == 0) ? 1 : 0;
+ r_P = calc_parity_8bit( r_AL );
+
+ result = ( (r_O & 1) << (16 + X86G_CC_SHIFT_O) )
+ | ( (r_S & 1) << (16 + X86G_CC_SHIFT_S) )
+ | ( (r_Z & 1) << (16 + X86G_CC_SHIFT_Z) )
+ | ( (r_A & 1) << (16 + X86G_CC_SHIFT_A) )
+ | ( (r_C & 1) << (16 + X86G_CC_SHIFT_C) )
+ | ( (r_P & 1) << (16 + X86G_CC_SHIFT_P) )
+ | ( (r_AH & 0xFF) << 8 )
+ | ( (r_AL & 0xFF) << 0 );
+ return result;
+}
+
+
/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (non-referentially-transparent) */
/* Horrible hack. On non-x86 platforms, return 1. */
Modified: branches/VEX_3_6_BRANCH/priv/guest_x86_toIR.c
===================================================================
--- branches/VEX_3_6_BRANCH/priv/guest_x86_toIR.c 2011-02-14 13:30:26 UTC (rev 2093)
+++ branches/VEX_3_6_BRANCH/priv/guest_x86_toIR.c 2011-02-14 13:33:36 UTC (rev 2094)
@@ -12907,26 +12907,52 @@
}
break;
-//-- case 0xD4: /* AAM */
-//-- case 0xD5: /* AAD */
-//-- d32 = getIByte(delta); delta++;
-//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
-//-- t1 = newTemp(cb);
-//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
-//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
-//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
-//-- uWiden(cb, 2, False);
-//-- uInstr0(cb, CALLM_S, 0);
-//-- uInstr1(cb, PUSH, 4, TempReg, t1);
-//-- uInstr1(cb, CALLM, 0, Lit16,
-//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
-//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
-//-- uInstr1(cb, POP, 4, TempReg, t1);
-//-- uInstr0(cb, CALLM_E, 0);
-//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
-//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
-//-- break;
+ case 0xD4: /* AAM */
+ case 0xD5: /* AAD */
+ d32 = getIByte(delta); delta++;
+ if (sz != 4 || d32 != 10) goto decode_failure;
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ /* Make up a 32-bit value (t1), with the old value of AX in the
+ bottom 16 bits, and the old OSZACP bitmask in the upper 16
+ bits. */
+ assign(t1,
+ binop(Iop_16HLto32,
+ unop(Iop_32to16,
+ mk_x86g_calculate_eflags_all()),
+ getIReg(2, R_EAX)
+ ));
+ /* Call the helper fn, to get a new AX and OSZACP value, and
+ poke both back into the guest state. Also pass the helper
+ the actual opcode so it knows which of the 2 instructions it
+ is doing the computation for. */
+ assign(t2,
+ mkIRExprCCall(
+ Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
+ &x86g_calculate_aad_aam,
+ mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
+ ));
+ putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
+ binop(Iop_And32,
+ binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
+ mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
+ | X86G_CC_MASK_A | X86G_CC_MASK_Z
+ | X86G_CC_MASK_S| X86G_CC_MASK_O )
+ )
+ )
+ );
+ /* Set NDEP even though it isn't used. This makes
+ redundant-PUT elimination of previous stores to this field
+ work better. */
+ stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
+
+ DIP(opc == 0xD4 ? "aam\n" : "aad\n");
+ break;
+
/* ------------------------ CWD/CDQ -------------------- */
case 0x98: /* CBW */
|