From 8995cedb4c13d9f8cfbbe4b4272251bd604af1c7 Mon Sep 17 00:00:00 2001
From: Aliaksey Kandratsenka <alk@tut.by>
Date: Fri, 3 May 2013 20:44:13 -0800
Subject: [PATCH 1/2] 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.
---
 src/windows/preamble_patcher.cc           |   36 +++++++++++++++++++++++++++++
 src/windows/preamble_patcher.h            |    8 +++++++
 src/windows/preamble_patcher_with_stub.cc |    5 ++++
 3 files changed, 49 insertions(+)

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) ||
-- 
1.7.10.4

