From: Julian Seward Date: Mon, 14 Feb 2011 13:33:36 +0000 (+0000) Subject: Merge from trunk, r2078 (Add support for AAD and AAM (base 10 only).) X-Git-Tag: svn/VALGRIND_3_6_1^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cecd6a06806f02eeeb5c2cf85804030c37895d5e;p=thirdparty%2Fvalgrind.git Merge from trunk, r2078 (Add support for AAD and AAM (base 10 only).) git-svn-id: svn://svn.valgrind.org/vex/branches/VEX_3_6_BRANCH@2094 --- diff --git a/VEX/priv/guest_x86_defs.h b/VEX/priv/guest_x86_defs.h index 09d647a9d9..96335335f1 100644 --- a/VEX/priv/guest_x86_defs.h +++ b/VEX/priv/guest_x86_defs.h @@ -108,6 +108,8 @@ extern ULong x86g_calculate_RCL ( 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 ); diff --git a/VEX/priv/guest_x86_helpers.c b/VEX/priv/guest_x86_helpers.c index 7aa7a3392a..c538c07662 100644 --- a/VEX/priv/guest_x86_helpers.c +++ b/VEX/priv/guest_x86_helpers.c @@ -2109,6 +2109,51 @@ UInt x86g_calculate_daa_das_aaa_aas ( UInt flags_and_AX, UInt opcode ) 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) */ diff --git a/VEX/priv/guest_x86_toIR.c b/VEX/priv/guest_x86_toIR.c index d03b6f1fa2..50a9e327e7 100644 --- a/VEX/priv/guest_x86_toIR.c +++ b/VEX/priv/guest_x86_toIR.c @@ -12907,25 +12907,51 @@ DisResult disInstr_X86_WRK ( } 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 -------------------- */