From: Julian Seward Date: Sat, 21 Apr 2012 10:47:41 +0000 (+0000) Subject: chainXDirect_ARM: generate direct jumps when possible. X-Git-Tag: svn/VALGRIND_3_8_1^2~177 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3cbb89b7da89556284af09a0e482304495b56189;p=thirdparty%2Fvalgrind.git chainXDirect_ARM: generate direct jumps when possible. git-svn-id: svn://svn.valgrind.org/vex/trunk@2301 --- diff --git a/VEX/priv/host_arm_defs.c b/VEX/priv/host_arm_defs.c index 755699ebe5..645027fda5 100644 --- a/VEX/priv/host_arm_defs.c +++ b/VEX/priv/host_arm_defs.c @@ -4516,18 +4516,62 @@ VexInvalRange chainXDirect_ARM ( void* place_to_chain, vassert(is_imm32_to_iregNo_EXACTLY2( p, /*r*/12, (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED))); vassert(p[2] == 0xE12FFF3C); - /* And what we want to change it to is: - movw r12, lo16(place_to_jump_to) - movt r12, hi16(place_to_jump_to) - bx r12 - viz - <8 bytes generated by imm32_to_iregNo_EXACTLY2> - E1 2F FF 1C - The replacement has the same length as the original. + /* And what we want to change it to is either: + (general case) + movw r12, lo16(place_to_jump_to) + movt r12, hi16(place_to_jump_to) + bx r12 + viz + <8 bytes generated by imm32_to_iregNo_EXACTLY2> + E1 2F FF 1C + ---OR--- + in the case where the displacement falls within 26 bits + b disp24; undef; undef + viz + EA <3 bytes == disp24> + FF 00 00 00 + FF 00 00 00 + + In both cases the replacement has the same length as the original. + To remain sane & verifiable, + (1) limit the displacement for the short form to + (say) +/- 30 million, so as to avoid wraparound + off-by-ones + (2) even if the short form is applicable, once every (say) + 1024 times use the long form anyway, so as to maintain + verifiability */ - (void)imm32_to_iregNo_EXACTLY2( - p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to)); - p[2] = 0xE12FFF1C; + + /* This is the delta we need to put into a B insn. It's relative + to the start of the next-but-one insn, hence the -8. */ + Long delta = (Long)((UChar*)place_to_jump_to - (UChar*)p) - (Long)8; + Bool shortOK = delta >= -30*1000*1000 && delta < 30*1000*1000; + vassert(0 == (delta & (Long)3)); + + static UInt shortCTR = 0; /* DO NOT MAKE NON-STATIC */ + if (shortOK) { + shortCTR++; // thread safety bleh + if (0 == (shortCTR & 0x3FF)) { + shortOK = False; + if (0) + vex_printf("QQQ chainXDirect_ARM: shortCTR = %u, " + "using long form\n", shortCTR); + } + } + + /* And make the modifications. */ + if (shortOK) { + Int simm24 = (Int)(delta >> 2); + vassert(simm24 == ((simm24 << 8) >> 8)); + p[0] = 0xEA000000 | (simm24 & 0x00FFFFFF); + p[1] = 0xFF000000; + p[2] = 0xFF000000; + } else { + (void)imm32_to_iregNo_EXACTLY2( + p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to)); + p[2] = 0xE12FFF1C; + } + VexInvalRange vir = {(HWord)p, 12}; return vir; } @@ -4540,18 +4584,44 @@ VexInvalRange unchainXDirect_ARM ( void* place_to_unchain, void* disp_cp_chain_me ) { /* What we're expecting to see is: - movw r12, lo16(place_to_jump_to_EXPECTED) - movt r12, lo16(place_to_jump_to_EXPECTED) - bx r12 - viz - <8 bytes generated by imm32_to_iregNo_EXACTLY2> - E1 2F FF 1C + (general case) + movw r12, lo16(place_to_jump_to_EXPECTED) + movt r12, lo16(place_to_jump_to_EXPECTED) + bx r12 + viz + <8 bytes generated by imm32_to_iregNo_EXACTLY2> + E1 2F FF 1C + ---OR--- + in the case where the displacement falls within 26 bits + b disp24; undef; undef + viz + EA <3 bytes == disp24> + FF 00 00 00 + FF 00 00 00 */ UInt* p = (UInt*)place_to_unchain; vassert(0 == (3 & (HWord)p)); - vassert(is_imm32_to_iregNo_EXACTLY2( - p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to_EXPECTED))); - vassert(p[2] == 0xE12FFF1C); + + Bool valid = False; + if (is_imm32_to_iregNo_EXACTLY2( + p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to_EXPECTED)) + && p[2] == 0xE12FFF1C) { + valid = True; /* it's the long form */ + if (0) + vex_printf("QQQ unchainXDirect_ARM: found long form\n"); + } else + if ((p[0] >> 24) == 0xEA && p[1] == 0xFF000000 && p[2] == 0xFF000000) { + /* It's the short form. Check the displacement is right. */ + Int simm24 = p[0] & 0x00FFFFFF; + simm24 <<= 8; simm24 >>= 8; + if ((UChar*)p + (simm24 << 2) + 8 == (UChar*)place_to_jump_to_EXPECTED) { + valid = True; + if (0) + vex_printf("QQQ unchainXDirect_ARM: found short form\n"); + } + } + vassert(valid); + /* And what we want to change it to is: movw r12, lo16(disp_cp_chain_me) movt r12, hi16(disp_cp_chain_me)