bt_literal.c is a somewhat halfhearted test case for it.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@76
}
-#if 0
-/* Group 8 extended opcodes. */
+
+/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
static
-Addr dis_Grp8 ( UCodeBlock* cb, Addr eip, UChar modrm,
- Int am_sz, Int sz, UInt src_val )
+Addr dis_Grp8_BT ( UCodeBlock* cb, Addr eip, UChar modrm,
+ Int am_sz, Int sz, UInt src_val )
{
+# define MODIFY_t2_AND_SET_CARRY_FLAG \
+ /* t2 is the value to be op'd on. Copy to t_fetched, then \
+ modify t2, if non-BT. */ \
+ uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
+ uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
+ uLiteral(cb, v_mask); \
+ switch (gregOfRM(modrm)) { \
+ case 4: /* BT */ break; \
+ case 5: /* BTS */ \
+ uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
+ case 6: /* BTR */ \
+ uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
+ case 7: /* BTC */ \
+ uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
+ } \
+ /* Copy relevant bit from t_fetched into carry flag. */ \
+ uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
+ uLiteral(cb, src_val); \
+ uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
+ uLiteral(cb, 1); \
+ uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
+ uInstr1(cb, NEG, sz, TempReg, t_fetched); \
+ setFlagsFromUOpcode(cb, NEG);
+
+
/* src_val denotes a d8.
And eip on entry points at the modrm byte. */
- Int t1, t2, helper;
+ Int t1, t2, t_fetched, t_mask;
UInt pair;
UChar dis_buf[50];
+ UInt v_mask;
+
+ /* There is no 1-byte form of this instruction, AFAICS. */
+ vg_assert(sz == 2 || sz == 4);
+
+ /* Limit src_val -- the bit offset -- to something within a word.
+ The Intel docs say that literal offsets larger than a word are
+ masked in this way. */
+ switch (sz) {
+ case 2: src_val &= 15; break;
+ case 4: src_val &= 31; break;
+ default: VG_(panic)("dis_Grp8_BT: invalid size");
+ }
+
+ /* Invent a mask suitable for the operation. */
switch (gregOfRM(modrm)) {
- case 4: helper = VGOFF_(helper_bt); break;
- case 5: helper = VGOFF_(helper_bts); break;
- case 6: helper = VGOFF_(helper_btr); break;
- case 7: helper = VGOFF_(helper_btc); break;
- /* If this needs to be extended, be careful to do the flag
- setting in the parts below correctly. */
- default: VG_(panic)("dis_Grp8");
+ case 4: /* BT */ v_mask = 0; break;
+ case 5: /* BTS */ v_mask = 1 << src_val; break;
+ case 6: /* BTR */ v_mask = ~(1 << src_val); break;
+ case 7: /* BTC */ v_mask = 1 << src_val; break;
+ /* If this needs to be extended, probably simplest to make a
+ new function to handle the other cases (0 .. 3). The
+ Intel docs do however not indicate any use for 0 .. 3, so
+ we don't expect this to happen. */
+ default: VG_(panic)("dis_Grp8_BT");
}
+ /* Probably excessively paranoid. */
+ if (sz == 2)
+ v_mask &= 0x0000FFFF;
+
+ t1 = INVALID_TEMPREG;
+ t_fetched = newTemp(cb);
+ t_mask = newTemp(cb);
- t1 = newTemp(cb);
- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
- uLiteral(cb, src_val);
- uInstr0(cb, CALLM_S, 0);
- uInstr1(cb, PUSH, 4, TempReg, t1);
-
if (epartIsReg(modrm)) {
vg_assert(am_sz == 1);
t2 = newTemp(cb);
- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
- uInstr1(cb, PUSH, sz, TempReg, t2);
- uInstr1(cb, CALLM, 0, Lit16, helper);
- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
- uInstr1(cb, POP, sz, TempReg, t2);
- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
- uInstr1(cb, CLEAR, 0, Lit16, 4);
+
+ /* Fetch the value to be tested and modified. */
+ uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
+ /* Do it! */
+ MODIFY_t2_AND_SET_CARRY_FLAG;
+ /* Dump the result back, if non-BT. */
+ if (gregOfRM(modrm) != 4 /* BT */)
+ uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
+
eip += (am_sz + 1);
if (dis)
VG_(printf)("%s%c $0x%x, %s\n",
t2 = newTemp(cb);
eip += HI8(pair);
eip += 1;
+
+ /* Fetch the value to be tested and modified. */
uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
- uInstr1(cb, PUSH, sz, TempReg, t2);
- uInstr1(cb, CALLM, 0, Lit16, helper);
- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
- uInstr1(cb, POP, sz, TempReg, t2);
- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
- SMC_IF_ALL(cb);
- uInstr1(cb, CLEAR, 0, Lit16, 4);
+ /* Do it! */
+ MODIFY_t2_AND_SET_CARRY_FLAG;
+ /* Dump the result back, if non-BT. */
+ if (gregOfRM(modrm) != 4 /* BT */) {
+ uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
+ SMC_IF_ALL(cb);
+ }
if (dis)
VG_(printf)("%s%c $0x%x, %s\n",
nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
dis_buf);
}
- uInstr0(cb, CALLM_E, 0);
return eip;
+
+# undef MODIFY_t2_AND_SET_CARRY_FLAG
}
-#endif
/* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
-#if 0
case 0xBA: /* Grp8 Ib,Ev */
modrm = getUChar(eip);
am_sz = lengthAMode(eip);
d32 = getSDisp8(eip + am_sz);
- eip = dis_Grp8 ( cb, eip, modrm, am_sz, sz, d32 );
+ eip = dis_Grp8_BT ( cb, eip, modrm, am_sz, sz, d32 );
break;
-#endif
+
/* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
case 0xBC: /* BSF Gv,Ev */
--- /dev/null
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+typedef unsigned int UInt;
+
+/* Given a word, do bt/bts/btr/btc on bits 0, 1, 2 and 3 of it, and
+ also reconstruct the original bits 0, 1, 2, 3 by looking at the
+ carry flag. Returned result has mashed bits 0-3 at the bottom and
+ the reconstructed original bits 0-3 as 4-7. */
+UInt mash_reg_L ( UInt orig )
+{
+ UInt reconstructed, mashed;
+ __asm__ __volatile__ (
+ "movl %2, %%edx\n\t"
+ ""
+ "movl $0, %%eax\n\t"
+ "\n\t"
+ "btl $0, %%edx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btsl $1, %%edx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $1, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btrl $2, %%edx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $2, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btcl $3, %%edx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $3, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "movl %%eax, %0\n\t"
+ "movl %%edx, %1"
+
+ : "=r" (reconstructed), "=r" (mashed)
+ : "r" (orig)
+ : "eax", "ecx", "edx", "cc");
+ return (mashed & 0xF) | ((reconstructed & 0xF) << 4);
+}
+
+
+
+
+UInt mash_mem_L ( UInt* origp )
+{
+ UInt reconstructed, mashed;
+ __asm__ __volatile__ (
+ "movl %2, %%edx\n\t"
+ ""
+ "movl $0, %%eax\n\t"
+ "\n\t"
+ "btl $0, (%%edx)\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btsl $1, (%%edx)\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $1, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btrl $2, (%%edx)\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $2, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btcl $3, (%%edx)\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $3, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "movl %%eax, %0\n\t"
+ "movl (%%edx), %1"
+
+ : "=r" (reconstructed), "=r" (mashed)
+ : "r" (origp)
+ : "eax", "ecx", "edx", "cc");
+ return (mashed & 0xF) | ((reconstructed & 0xF) << 4);
+}
+
+
+
+UInt mash_reg_W ( UInt orig )
+{
+ UInt reconstructed, mashed;
+ __asm__ __volatile__ (
+ "movl %2, %%edx\n\t"
+ ""
+ "movl $0, %%eax\n\t"
+ "\n\t"
+ "btw $0, %%dx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btsw $1, %%dx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $1, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btrw $2, %%dx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $2, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "btcw $3, %%dx\n\t"
+ "setb %%cl\n\t"
+ "movzbl %%cl, %%ecx\n\t"
+ "shll $3, %%ecx\n\t"
+ "orl %%ecx, %%eax\n\t"
+ "\n\t"
+ "movl %%eax, %0\n\t"
+ "movl %%edx, %1"
+
+ : "=r" (reconstructed), "=r" (mashed)
+ : "r" (orig)
+ : "eax", "ecx", "edx", "cc");
+ return (mashed & 0xF) | ((reconstructed & 0xF) << 4);
+}
+
+
+
+
+int main ( void )
+{
+ int i, ii;
+ for (i = 0; i < 0x10; i++) {
+ ii = i;
+ printf("0x%x -> 0x%2x 0x%2x 0x%2x\n", i,
+ mash_reg_L(i), mash_mem_L(&ii), mash_reg_W(i));
+ }
+ return 1;
+}
+
}
-#if 0
-/* Group 8 extended opcodes. */
+
+/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
static
-Addr dis_Grp8 ( UCodeBlock* cb, Addr eip, UChar modrm,
- Int am_sz, Int sz, UInt src_val )
+Addr dis_Grp8_BT ( UCodeBlock* cb, Addr eip, UChar modrm,
+ Int am_sz, Int sz, UInt src_val )
{
+# define MODIFY_t2_AND_SET_CARRY_FLAG \
+ /* t2 is the value to be op'd on. Copy to t_fetched, then \
+ modify t2, if non-BT. */ \
+ uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
+ uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
+ uLiteral(cb, v_mask); \
+ switch (gregOfRM(modrm)) { \
+ case 4: /* BT */ break; \
+ case 5: /* BTS */ \
+ uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
+ case 6: /* BTR */ \
+ uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
+ case 7: /* BTC */ \
+ uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
+ } \
+ /* Copy relevant bit from t_fetched into carry flag. */ \
+ uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
+ uLiteral(cb, src_val); \
+ uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
+ uLiteral(cb, 1); \
+ uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
+ uInstr1(cb, NEG, sz, TempReg, t_fetched); \
+ setFlagsFromUOpcode(cb, NEG);
+
+
/* src_val denotes a d8.
And eip on entry points at the modrm byte. */
- Int t1, t2, helper;
+ Int t1, t2, t_fetched, t_mask;
UInt pair;
UChar dis_buf[50];
+ UInt v_mask;
+
+ /* There is no 1-byte form of this instruction, AFAICS. */
+ vg_assert(sz == 2 || sz == 4);
+
+ /* Limit src_val -- the bit offset -- to something within a word.
+ The Intel docs say that literal offsets larger than a word are
+ masked in this way. */
+ switch (sz) {
+ case 2: src_val &= 15; break;
+ case 4: src_val &= 31; break;
+ default: VG_(panic)("dis_Grp8_BT: invalid size");
+ }
+
+ /* Invent a mask suitable for the operation. */
switch (gregOfRM(modrm)) {
- case 4: helper = VGOFF_(helper_bt); break;
- case 5: helper = VGOFF_(helper_bts); break;
- case 6: helper = VGOFF_(helper_btr); break;
- case 7: helper = VGOFF_(helper_btc); break;
- /* If this needs to be extended, be careful to do the flag
- setting in the parts below correctly. */
- default: VG_(panic)("dis_Grp8");
+ case 4: /* BT */ v_mask = 0; break;
+ case 5: /* BTS */ v_mask = 1 << src_val; break;
+ case 6: /* BTR */ v_mask = ~(1 << src_val); break;
+ case 7: /* BTC */ v_mask = 1 << src_val; break;
+ /* If this needs to be extended, probably simplest to make a
+ new function to handle the other cases (0 .. 3). The
+ Intel docs do however not indicate any use for 0 .. 3, so
+ we don't expect this to happen. */
+ default: VG_(panic)("dis_Grp8_BT");
}
+ /* Probably excessively paranoid. */
+ if (sz == 2)
+ v_mask &= 0x0000FFFF;
+
+ t1 = INVALID_TEMPREG;
+ t_fetched = newTemp(cb);
+ t_mask = newTemp(cb);
- t1 = newTemp(cb);
- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
- uLiteral(cb, src_val);
- uInstr0(cb, CALLM_S, 0);
- uInstr1(cb, PUSH, 4, TempReg, t1);
-
if (epartIsReg(modrm)) {
vg_assert(am_sz == 1);
t2 = newTemp(cb);
- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
- uInstr1(cb, PUSH, sz, TempReg, t2);
- uInstr1(cb, CALLM, 0, Lit16, helper);
- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
- uInstr1(cb, POP, sz, TempReg, t2);
- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
- uInstr1(cb, CLEAR, 0, Lit16, 4);
+
+ /* Fetch the value to be tested and modified. */
+ uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
+ /* Do it! */
+ MODIFY_t2_AND_SET_CARRY_FLAG;
+ /* Dump the result back, if non-BT. */
+ if (gregOfRM(modrm) != 4 /* BT */)
+ uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
+
eip += (am_sz + 1);
if (dis)
VG_(printf)("%s%c $0x%x, %s\n",
t2 = newTemp(cb);
eip += HI8(pair);
eip += 1;
+
+ /* Fetch the value to be tested and modified. */
uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
- uInstr1(cb, PUSH, sz, TempReg, t2);
- uInstr1(cb, CALLM, 0, Lit16, helper);
- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
- uInstr1(cb, POP, sz, TempReg, t2);
- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
- SMC_IF_ALL(cb);
- uInstr1(cb, CLEAR, 0, Lit16, 4);
+ /* Do it! */
+ MODIFY_t2_AND_SET_CARRY_FLAG;
+ /* Dump the result back, if non-BT. */
+ if (gregOfRM(modrm) != 4 /* BT */) {
+ uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
+ SMC_IF_ALL(cb);
+ }
if (dis)
VG_(printf)("%s%c $0x%x, %s\n",
nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
dis_buf);
}
- uInstr0(cb, CALLM_E, 0);
return eip;
+
+# undef MODIFY_t2_AND_SET_CARRY_FLAG
}
-#endif
/* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
-#if 0
case 0xBA: /* Grp8 Ib,Ev */
modrm = getUChar(eip);
am_sz = lengthAMode(eip);
d32 = getSDisp8(eip + am_sz);
- eip = dis_Grp8 ( cb, eip, modrm, am_sz, sz, d32 );
+ eip = dis_Grp8_BT ( cb, eip, modrm, am_sz, sz, d32 );
break;
-#endif
+
/* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
case 0xBC: /* BSF Gv,Ev */