diff options
author | alkondratenko@gmail.com <alkondratenko@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50> | 2013-05-07 19:13:29 +0000 |
---|---|---|
committer | alkondratenko@gmail.com <alkondratenko@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50> | 2013-05-07 19:13:29 +0000 |
commit | 7fcb5ac0696e7ef7f7e7e51c18745af25de7da96 (patch) | |
tree | 2f1d199e405c983871322345a60ee761f4b05557 | |
parent | 8cb4086a0aee539869bd087a85881788545b23d6 (diff) | |
download | gperftools-7fcb5ac0696e7ef7f7e7e51c18745af25de7da96.tar.gz |
issue-511: implemented rel8 jump patching
I've found that Visual Studio 2012 release 32-bit C runtime library
patching fails because array new has rel8 jmp which previous code
could not handle.
Implementation is largely copied from conditional jumps handling code.
git-svn-id: http://gperftools.googlecode.com/svn/trunk@213 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
-rw-r--r-- | src/windows/preamble_patcher.cc | 36 | ||||
-rw-r--r-- | src/windows/preamble_patcher.h | 8 | ||||
-rw-r--r-- | src/windows/preamble_patcher_with_stub.cc | 5 |
3 files changed, 49 insertions, 0 deletions
diff --git a/src/windows/preamble_patcher.cc b/src/windows/preamble_patcher.cc index b27a95b..4163691 100644 --- a/src/windows/preamble_patcher.cc +++ b/src/windows/preamble_patcher.cc @@ -535,6 +535,12 @@ bool PreamblePatcher::IsShortConditionalJump( return (*(target) & 0x70) == 0x70 && instruction_size == 2; } +bool PreamblePatcher::IsShortJump( + unsigned char* target, + unsigned int instruction_size) { + return target[0] == 0xeb && instruction_size == 2; +} + bool PreamblePatcher::IsNearConditionalJump( unsigned char* target, unsigned int instruction_size) { @@ -600,6 +606,36 @@ SideStepError PreamblePatcher::PatchShortConditionalJump( return SIDESTEP_SUCCESS; } +SideStepError PreamblePatcher::PatchShortJump( + unsigned char* source, + unsigned int instruction_size, + unsigned char* target, + unsigned int* target_bytes, + unsigned int target_size) { + // note: rel8 offset is _signed_. Thus we need signed char here. + unsigned char* original_jump_dest = (source + 2) + static_cast<signed char>(source[1]); + unsigned char* stub_jump_from = target + 5; + __int64 fixup_jump_offset = original_jump_dest - stub_jump_from; + if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) { + SIDESTEP_ASSERT(false && + "Unable to fix up short jump because target" + " is too far away."); + return SIDESTEP_JUMP_INSTRUCTION; + } + + *target_bytes = 5; + if (target_size > *target_bytes) { + // Convert the short jump to a near jump. + // + // e9 xx xx xx xx = jmp rel32off + target[0] = 0xe9; + memcpy(reinterpret_cast<void*>(target + 1), + reinterpret_cast<void*>(&fixup_jump_offset), 4); + } + + return SIDESTEP_SUCCESS; +} + SideStepError PreamblePatcher::PatchNearJumpOrCall( unsigned char* source, unsigned int instruction_size, diff --git a/src/windows/preamble_patcher.h b/src/windows/preamble_patcher.h index 4fdb7d0..8a90258 100644 --- a/src/windows/preamble_patcher.h +++ b/src/windows/preamble_patcher.h @@ -467,6 +467,8 @@ class PERFTOOLS_DLL_DECL PreamblePatcher { static bool IsShortConditionalJump(unsigned char* target, unsigned int instruction_size); + static bool IsShortJump(unsigned char *target, unsigned int instruction_size); + // Helper routine that determines if a target instruction is a near // conditional jump. // @@ -547,6 +549,12 @@ class PERFTOOLS_DLL_DECL PreamblePatcher { unsigned int* target_bytes, unsigned int target_size); + static SideStepError PatchShortJump(unsigned char* source, + unsigned int instruction_size, + unsigned char* target, + unsigned int* target_bytes, + unsigned int target_size); + // Helper routine that converts an instruction that will convert various // jump-like instructions to corresponding instructions in the target buffer. // What this routine does is fix up the relative offsets contained in jump diff --git a/src/windows/preamble_patcher_with_stub.cc b/src/windows/preamble_patcher_with_stub.cc index b0dc393..4c1d1c7 100644 --- a/src/windows/preamble_patcher_with_stub.cc +++ b/src/windows/preamble_patcher_with_stub.cc @@ -150,6 +150,11 @@ SideStepError PreamblePatcher::RawPatchWithStub( preamble_stub + stub_bytes, &jump_bytes, stub_size - stub_bytes); + } else if (IsShortJump(target + preamble_bytes, cur_bytes)) { + jump_ret = PatchShortJump(target + preamble_bytes, cur_bytes, + preamble_stub + stub_bytes, + &jump_bytes, + stub_size - stub_bytes); } else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) || IsNearRelativeJump(target + preamble_bytes, cur_bytes) || IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) || |