From 05207b35080283107e3f9607165f092244838ee9 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Tue, 16 Apr 2002 00:42:12 +0000 Subject: [PATCH] Relent, and properly implement bt/bts/btc/btr for literal bit-offsets. bt_literal.c is a somewhat halfhearted test case for it. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@76 --- coregrind/vg_to_ucode.c | 120 ++++++++++++++++++++++---------- tests/bt_literal.c | 150 ++++++++++++++++++++++++++++++++++++++++ vg_to_ucode.c | 120 ++++++++++++++++++++++---------- 3 files changed, 316 insertions(+), 74 deletions(-) create mode 100644 tests/bt_literal.c diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c index 79519f48d9..1998c8ee32 100644 --- a/coregrind/vg_to_ucode.c +++ b/coregrind/vg_to_ucode.c @@ -1219,44 +1219,89 @@ Addr dis_Grp2 ( UCodeBlock* cb, Addr eip, UChar modrm, } -#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", @@ -1269,23 +1314,25 @@ Addr dis_Grp8 ( UCodeBlock* cb, Addr eip, UChar modrm, 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 @@ -4044,14 +4091,13 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) /* =-=-=-=-=-=-=-=-=- 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 */ diff --git a/tests/bt_literal.c b/tests/bt_literal.c new file mode 100644 index 0000000000..3f7e764f1d --- /dev/null +++ b/tests/bt_literal.c @@ -0,0 +1,150 @@ + +#include +#include +#include + +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; +} + diff --git a/vg_to_ucode.c b/vg_to_ucode.c index 79519f48d9..1998c8ee32 100644 --- a/vg_to_ucode.c +++ b/vg_to_ucode.c @@ -1219,44 +1219,89 @@ Addr dis_Grp2 ( UCodeBlock* cb, Addr eip, UChar modrm, } -#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", @@ -1269,23 +1314,25 @@ Addr dis_Grp8 ( UCodeBlock* cb, Addr eip, UChar modrm, 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 @@ -4044,14 +4091,13 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) /* =-=-=-=-=-=-=-=-=- 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 */ -- 2.47.3