Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: courgette/rel32_finder_x64.cc

Issue 2008253004: Refactor rel32 searching process for x64 to make it more similar to x86. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rollback to original courgette algorithm and improve unittests Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/rel32_finder_x64.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "courgette/assembly_program.h"
12 #include "courgette/courgette.h"
13
14 #if COURGETTE_HISTOGRAM_TARGETS
15 #include <iostream>
16 #endif
17 6
18 namespace courgette { 7 namespace courgette {
19 8
20 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) 9 Rel32FinderX64::Rel32FinderX64(RVA relocs_start_rva, RVA relocs_end_rva)
21 : DisassemblerWin32(start, length) {} 10 : Rel32Finder(relocs_start_rva, relocs_end_rva) {}
22 11
23 RVA DisassemblerWin32X64::PointerToTargetRVA(const uint8_t* p) const { 12 void Rel32FinderX64::Find(const uint8_t* start_pointer,
24 return Address64ToRVA(Read64LittleEndian(p)); 13 const uint8_t* end_pointer,
25 } 14 RVA start_rva,
26 15 RVA end_rva,
27 RVA DisassemblerWin32X64::Address64ToRVA(uint64_t address) const { 16 uint32_t size_of_image,
28 if (address < image_base() || address >= image_base() + size_of_image_) 17 const std::vector<RVA>& abs32_locations) {
29 return kNoRVA;
30 return base::checked_cast<RVA>(address - image_base());
31 }
32
33 CheckBool DisassemblerWin32X64::EmitAbs(Label* label,
34 AssemblyProgram* program) {
35 return program->EmitAbs64(label);
36 }
37
38 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) {
39 // TODO(sra): use characteristic.
40 bool isCode = strcmp(section->name, ".text") == 0;
41 if (!isCode)
42 return;
43
44 FileOffset start_file_offset = section->file_offset_of_raw_data;
45 FileOffset end_file_offset = start_file_offset + section->size_of_raw_data;
46 RVA relocs_start_rva = base_relocation_table().address_;
47
48 const uint8_t* start_pointer = FileOffsetToPointer(start_file_offset);
49 const uint8_t* end_pointer = FileOffsetToPointer(end_file_offset);
50
51 RVA start_rva = FileOffsetToRVA(start_file_offset);
52 RVA end_rva = start_rva + section->virtual_size;
53
54 // Quick way to convert from Pointer to RVA within a single Section is to 18 // Quick way to convert from Pointer to RVA within a single Section is to
55 // subtract |pointer_to_rva|. 19 // subtract 'pointer_to_rva'.
huangs 2016/05/26 22:11:17 NIT: |adjust_pointer_to_rva|.
etiennep 2016/05/27 18:12:34 Done.
56 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; 20 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva;
57 21
58 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); 22 std::vector<RVA>::const_iterator abs32_pos = abs32_locations.begin();
59 23
60 // Find the rel32 relocations. 24 // Find the rel32 relocations.
61 const uint8_t* p = start_pointer; 25 const uint8_t* p = start_pointer;
62 while (p < end_pointer) { 26 while (p < end_pointer) {
63 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); 27 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
64 if (current_rva == relocs_start_rva) { 28
65 uint32_t relocs_size = base_relocation_table().size_; 29 // Skip the base reloation table if we encounter it.
66 if (relocs_size) { 30 // Note: We're not bothering to handle the edge case where a Rel32 pointer
67 p += relocs_size; 31 // collides with |relocs_start_rva_| by being {1, 2, 3}-bytes before it.
68 continue; 32 if (current_rva >= relocs_start_rva_ && current_rva < relocs_end_rva_) {
69 } 33 p += relocs_end_rva_ - current_rva;
34 continue;
70 } 35 }
71 36
72 // Heuristic discovery of rel32 locations in instruction stream: are the 37 // Heuristic discovery of rel32 locations in instruction stream: are the
73 // next few bytes the start of an instruction containing a rel32 38 // next few bytes the start of an instruction containing a rel32
74 // addressing mode? 39 // addressing mode?
75 const uint8_t* rel32 = nullptr; 40 const uint8_t* rel32 = nullptr;
76 bool is_rip_relative = false; 41 bool is_rip_relative = false;
77 42
78 if (p + 5 <= end_pointer) { 43 if (p + 5 <= end_pointer) {
79 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 44 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32
80 rel32 = p + 1; 45 rel32 = p + 1;
81 } 46 }
82 if (p + 6 <= end_pointer) { 47 if (p + 6 <= end_pointer) {
83 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form 48 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form
84 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely 49 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely
85 rel32 = p + 2; 50 rel32 = p + 2;
86 } else if (*p == 0xFF && (*(p + 1) == 0x15 || *(p + 1) == 0x25)) { 51 } else if (*p == 0xFF && (*(p + 1) == 0x15 || *(p + 1) == 0x25)) {
87 // rip relative call/jmp 52 // rip relative call/jmp
88 rel32 = p + 2; 53 rel32 = p + 2;
89 is_rip_relative = true; 54 is_rip_relative = true;
90 } 55 }
91 } 56 }
92 if (p + 7 <= end_pointer) { 57 if (p + 7 <= end_pointer) {
93 if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8D && 58 if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8D &&
huangs 2016/05/26 22:11:17 Comments on these instructions?
etiennep 2016/05/27 18:12:34 Done.
94 (*(p + 2) & 0xC7) == 0x05) { 59 (*(p + 2) & 0xC7) == 0x05) {
95 // rip relative lea 60 // rip relative lea
96 rel32 = p + 3; 61 rel32 = p + 3;
97 is_rip_relative = true; 62 is_rip_relative = true;
98 } else if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8B && 63 } else if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8B &&
99 (*(p + 2) & 0xC7) == 0x05) { 64 (*(p + 2) & 0xC7) == 0x05) {
100 // rip relative mov 65 // rip relative mov
101 rel32 = p + 3; 66 rel32 = p + 3;
102 is_rip_relative = true; 67 is_rip_relative = true;
103 } 68 }
104 } 69 }
105 70
106 if (rel32) { 71 if (rel32) {
107 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); 72 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva);
108 73
109 // Is there an abs32 reloc overlapping the candidate? 74 // Is there an abs32 reloc overlapping the candidate?
110 while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3) 75 while (abs32_pos != abs32_locations.end() && *abs32_pos < rel32_rva - 3)
111 ++abs32_pos; 76 ++abs32_pos;
112 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte 77 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte
113 // region that could overlap rel32_rva. 78 // region that could overlap rel32_rva.
114 if (abs32_pos != abs32_locations_.end()) { 79 if (abs32_pos != abs32_locations.end()) {
115 if (*abs32_pos < rel32_rva + 4) { 80 if (*abs32_pos < rel32_rva + 4) {
116 // Beginning of abs32 reloc is before end of rel32 reloc so they 81 // Beginning of abs32 reloc is before end of rel32 reloc so they
117 // overlap. Skip four bytes past the abs32 reloc. 82 // overlap. Skip four bytes past the abs32 reloc.
huangs 2016/05/26 22:11:17 NIT: Remove space before "Skip".
etiennep 2016/05/27 18:12:34 Done.
118 p += (*abs32_pos + 4) - current_rva; 83 p += (*abs32_pos + 4) - current_rva;
119 continue; 84 continue;
120 } 85 }
121 } 86 }
122 87
huangs 2016/05/26 22:40:55 Why did the comment disappear?
etiennep 2016/05/27 18:12:34 Idk, it's back now!
123 // + 4 since offset is relative to start of next instruction.
124 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32); 88 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32);
125 // To be valid, rel32 target must be within image, and within this 89 // To be valid, rel32 target must be within image, and within this
126 // section. 90 // section.
127 if (target_rva < size_of_image_ && // Subsumes rva != kUnassignedRVA. 91 if (target_rva < size_of_image && // Subsumes rva != kUnassignedRVA.
huangs 2016/05/26 22:40:55 target_rva < size_of_image seems kinda bogus and
etiennep 2016/05/27 18:12:34 I moved size_of_image as an member variable. It wo
128 (is_rip_relative || 92 (is_rip_relative ||
129 (start_rva <= target_rva && target_rva < end_rva))) { 93 (start_rva <= target_rva && target_rva < end_rva))) {
130 rel32_locations_.push_back(rel32_rva); 94 rel32_locations_.push_back(rel32_rva);
131 #if COURGETTE_HISTOGRAM_TARGETS 95 #if COURGETTE_HISTOGRAM_TARGETS
132 ++rel32_target_rvas_[target_rva]; 96 ++rel32_target_rvas_[target_rva];
133 #endif 97 #endif
134 p = rel32 + 4; 98 p = rel32 + 4;
135 continue; 99 continue;
136 } 100 }
137 } 101 }
138 p += 1; 102 p += 1;
139 } 103 }
140 } 104 }
141 105
142 } // namespace courgette 106 } // namespace courgette
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698