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 |