summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralkondratenko@gmail.com <alkondratenko@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2013-05-07 19:13:29 +0000
committeralkondratenko@gmail.com <alkondratenko@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2013-05-07 19:13:29 +0000
commit7fcb5ac0696e7ef7f7e7e51c18745af25de7da96 (patch)
tree2f1d199e405c983871322345a60ee761f4b05557
parent8cb4086a0aee539869bd087a85881788545b23d6 (diff)
downloadgperftools-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.cc36
-rw-r--r--src/windows/preamble_patcher.h8
-rw-r--r--src/windows/preamble_patcher_with_stub.cc5
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) ||