| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "courgette/disassembler_win32_x64.h" | 5 #include "courgette/disassembler_win32_x64.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/numerics/safe_conversions.h" | 10 #include "base/numerics/safe_conversions.h" |
| 11 #include "courgette/assembly_program.h" | 11 #include "courgette/assembly_program.h" |
| 12 #include "courgette/courgette.h" | 12 #include "courgette/courgette.h" |
| 13 #include "courgette/rel32_finder_x64.h" |
| 13 | 14 |
| 14 #if COURGETTE_HISTOGRAM_TARGETS | 15 #if COURGETTE_HISTOGRAM_TARGETS |
| 15 #include <iostream> | 16 #include <iostream> |
| 16 #endif | 17 #endif |
| 17 | 18 |
| 18 namespace courgette { | 19 namespace courgette { |
| 19 | 20 |
| 20 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) | 21 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) |
| 21 : DisassemblerWin32(start, length) {} | 22 : DisassemblerWin32(start, length) {} |
| 22 | 23 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 36 } | 37 } |
| 37 | 38 |
| 38 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) { | 39 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) { |
| 39 // TODO(sra): use characteristic. | 40 // TODO(sra): use characteristic. |
| 40 bool isCode = strcmp(section->name, ".text") == 0; | 41 bool isCode = strcmp(section->name, ".text") == 0; |
| 41 if (!isCode) | 42 if (!isCode) |
| 42 return; | 43 return; |
| 43 | 44 |
| 44 FileOffset start_file_offset = section->file_offset_of_raw_data; | 45 FileOffset start_file_offset = section->file_offset_of_raw_data; |
| 45 FileOffset end_file_offset = start_file_offset + section->size_of_raw_data; | 46 FileOffset end_file_offset = start_file_offset + section->size_of_raw_data; |
| 46 RVA relocs_start_rva = base_relocation_table().address_; | |
| 47 | 47 |
| 48 const uint8_t* start_pointer = FileOffsetToPointer(start_file_offset); | 48 const uint8_t* start_pointer = FileOffsetToPointer(start_file_offset); |
| 49 const uint8_t* end_pointer = FileOffsetToPointer(end_file_offset); | 49 const uint8_t* end_pointer = FileOffsetToPointer(end_file_offset); |
| 50 | 50 |
| 51 RVA start_rva = FileOffsetToRVA(start_file_offset); | 51 RVA start_rva = FileOffsetToRVA(start_file_offset); |
| 52 RVA end_rva = start_rva + section->virtual_size; | 52 RVA end_rva = start_rva + section->virtual_size; |
| 53 | 53 |
| 54 // Quick way to convert from Pointer to RVA within a single Section is to | 54 Rel32FinderX64 finder( |
| 55 // subtract |pointer_to_rva|. | 55 base_relocation_table().address_, |
| 56 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; | 56 base_relocation_table().address_ + base_relocation_table().size_, |
| 57 size_of_image_); |
| 58 finder.Find(start_pointer, end_pointer, start_rva, end_rva, abs32_locations_); |
| 59 finder.SwapRel32Locations(&rel32_locations_); |
| 57 | 60 |
| 58 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); | |
| 59 | |
| 60 // Find the rel32 relocations. | |
| 61 const uint8_t* p = start_pointer; | |
| 62 while (p < end_pointer) { | |
| 63 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); | |
| 64 if (current_rva == relocs_start_rva) { | |
| 65 uint32_t relocs_size = base_relocation_table().size_; | |
| 66 if (relocs_size) { | |
| 67 p += relocs_size; | |
| 68 continue; | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 // Heuristic discovery of rel32 locations in instruction stream: are the | |
| 73 // next few bytes the start of an instruction containing a rel32 | |
| 74 // addressing mode? | |
| 75 const uint8_t* rel32 = nullptr; | |
| 76 bool is_rip_relative = false; | |
| 77 | |
| 78 if (p + 5 <= end_pointer) { | |
| 79 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 | |
| 80 rel32 = p + 1; | |
| 81 } | |
| 82 if (p + 6 <= end_pointer) { | |
| 83 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form | |
| 84 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely | |
| 85 rel32 = p + 2; | |
| 86 } else if (*p == 0xFF && (*(p + 1) == 0x15 || *(p + 1) == 0x25)) { | |
| 87 // rip relative call/jmp | |
| 88 rel32 = p + 2; | |
| 89 is_rip_relative = true; | |
| 90 } | |
| 91 } | |
| 92 if (p + 7 <= end_pointer) { | |
| 93 if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8D && | |
| 94 (*(p + 2) & 0xC7) == 0x05) { | |
| 95 // rip relative lea | |
| 96 rel32 = p + 3; | |
| 97 is_rip_relative = true; | |
| 98 } else if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8B && | |
| 99 (*(p + 2) & 0xC7) == 0x05) { | |
| 100 // rip relative mov | |
| 101 rel32 = p + 3; | |
| 102 is_rip_relative = true; | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 if (rel32) { | |
| 107 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); | |
| 108 | |
| 109 // Is there an abs32 reloc overlapping the candidate? | |
| 110 while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3) | |
| 111 ++abs32_pos; | |
| 112 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte | |
| 113 // region that could overlap rel32_rva. | |
| 114 if (abs32_pos != abs32_locations_.end()) { | |
| 115 if (*abs32_pos < rel32_rva + 4) { | |
| 116 // Beginning of abs32 reloc is before end of rel32 reloc so they | |
| 117 // overlap. Skip four bytes past the abs32 reloc. | |
| 118 p += (*abs32_pos + 4) - current_rva; | |
| 119 continue; | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 // + 4 since offset is relative to start of next instruction. | |
| 124 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32); | |
| 125 // To be valid, rel32 target must be within image, and within this | |
| 126 // section. | |
| 127 if (target_rva < size_of_image_ && // Subsumes rva != kUnassignedRVA. | |
| 128 (is_rip_relative || | |
| 129 (start_rva <= target_rva && target_rva < end_rva))) { | |
| 130 rel32_locations_.push_back(rel32_rva); | |
| 131 #if COURGETTE_HISTOGRAM_TARGETS | 61 #if COURGETTE_HISTOGRAM_TARGETS |
| 132 ++rel32_target_rvas_[target_rva]; | 62 DCHECK(rel32_target_rvas_.empty()); |
| 63 finder.SwapRel32TargetRVAs(&rel32_target_rvas_); |
| 133 #endif | 64 #endif |
| 134 p = rel32 + 4; | |
| 135 continue; | |
| 136 } | |
| 137 } | |
| 138 p += 1; | |
| 139 } | |
| 140 } | 65 } |
| 141 | 66 |
| 142 } // namespace courgette | 67 } // namespace courgette |
| OLD | NEW |