[email protected] | c23654ea | 2012-07-26 18:34:24 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "courgette/disassembler_elf_32_x86.h" |
| 6 | |
mostynb | 1007a4a | 2016-04-11 23:18:06 | [diff] [blame] | 7 | #include <memory> |
etiennep | 7d4e8ee | 2016-05-11 20:13:36 | [diff] [blame] | 8 | #include <utility> |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 9 | #include <vector> |
| 10 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 11 | #include "base/logging.h" |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 12 | #include "courgette/assembly_program.h" |
| 13 | #include "courgette/courgette.h" |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 14 | |
| 15 | namespace courgette { |
| 16 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 17 | CheckBool DisassemblerElf32X86::TypedRVAX86::ComputeRelativeTarget( |
| 18 | const uint8_t* op_pointer) { |
| 19 | set_relative_target(Read32LittleEndian(op_pointer) + 4); |
| 20 | return true; |
huangs | 58b822d4 | 2016-03-12 20:56:11 | [diff] [blame] | 21 | } |
| 22 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 23 | CheckBool DisassemblerElf32X86::TypedRVAX86::EmitInstruction( |
huangs | 7b221a5 | 2016-11-09 22:28:23 | [diff] [blame] | 24 | Label* label, |
| 25 | InstructionReceptor* receptor) { |
| 26 | return receptor->EmitRel32(label); |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 27 | } |
| 28 | |
| 29 | uint16_t DisassemblerElf32X86::TypedRVAX86::op_size() const { |
| 30 | return 4; |
| 31 | } |
| 32 | |
etiennep | 5059bca | 2016-07-08 17:55:20 | [diff] [blame] | 33 | DisassemblerElf32X86::DisassemblerElf32X86(const uint8_t* start, size_t length) |
| 34 | : DisassemblerElf32(start, length) {} |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 35 | |
| 36 | // Convert an ELF relocation struction into an RVA. |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 37 | CheckBool DisassemblerElf32X86::RelToRVA(Elf32_Rel rel, RVA* result) const { |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 38 | // The rightmost byte of r_info is the type. |
scottmg | 4a95ca5 | 2016-03-12 23:54:56 | [diff] [blame] | 39 | elf32_rel_386_type_values type = |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 40 | static_cast<elf32_rel_386_type_values>(rel.r_info & 0xFF); |
scottmg | 4a95ca5 | 2016-03-12 23:54:56 | [diff] [blame] | 41 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 42 | // The other 3 bytes of r_info are the symbol. |
avi | ab98dcc9 | 2015-12-21 19:35:33 | [diff] [blame] | 43 | uint32_t symbol = rel.r_info >> 8; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 44 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 45 | switch (type) { |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 46 | case R_386_NONE: |
| 47 | case R_386_32: |
| 48 | case R_386_PC32: |
| 49 | case R_386_GOT32: |
| 50 | case R_386_PLT32: |
| 51 | case R_386_COPY: |
| 52 | case R_386_GLOB_DAT: |
| 53 | case R_386_JMP_SLOT: |
| 54 | return false; |
| 55 | |
| 56 | case R_386_RELATIVE: |
| 57 | if (symbol != 0) |
| 58 | return false; |
| 59 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 60 | // This is a basic ABS32 relocation address. |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 61 | *result = rel.r_offset; |
| 62 | return true; |
| 63 | |
| 64 | case R_386_GOTOFF: |
| 65 | case R_386_GOTPC: |
| 66 | case R_386_TLS_TPOFF: |
| 67 | return false; |
| 68 | } |
| 69 | |
| 70 | return false; |
| 71 | } |
| 72 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 73 | CheckBool DisassemblerElf32X86::ParseRelocationSection( |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 74 | const Elf32_Shdr* section_header, |
huangs | 7b221a5 | 2016-11-09 22:28:23 | [diff] [blame] | 75 | InstructionReceptor* receptor) const { |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 76 | // We can reproduce the R_386_RELATIVE entries in one of the relocation table |
| 77 | // based on other information in the patch, given these conditions: |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 78 | // |
| 79 | // All R_386_RELATIVE entries are: |
| 80 | // 1) In the same relocation table |
| 81 | // 2) Are consecutive |
| 82 | // 3) Are sorted in memory address order |
| 83 | // |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 84 | // Happily, this is normally the case, but it's not required by spec, so we |
| 85 | // check, and just don't do it if we don't match up. |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 86 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 87 | // The expectation is that one relocation section will contain all of our |
| 88 | // R_386_RELATIVE entries in the expected order followed by assorted other |
| 89 | // entries we can't use special handling for. |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 90 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 91 | bool match = true; |
| 92 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 93 | // Walk all the bytes in the section, matching relocation table or not. |
| 94 | FileOffset file_offset = section_header->sh_offset; |
| 95 | FileOffset section_end = file_offset + section_header->sh_size; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 96 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 97 | const Elf32_Rel* section_relocs_iter = reinterpret_cast<const Elf32_Rel*>( |
| 98 | FileOffsetToPointer(section_header->sh_offset)); |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 99 | |
avi | ab98dcc9 | 2015-12-21 19:35:33 | [diff] [blame] | 100 | uint32_t section_relocs_count = |
| 101 | section_header->sh_size / section_header->sh_entsize; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 102 | |
Will Harris | 3e6fa97 | 2015-03-02 21:14:25 | [diff] [blame] | 103 | if (abs32_locations_.empty()) |
| 104 | match = false; |
| 105 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 106 | if (abs32_locations_.size() > section_relocs_count) |
| 107 | match = false; |
| 108 | |
huangs | 257f9fb0 | 2017-03-23 23:17:50 | [diff] [blame] | 109 | std::vector<RVA>::const_iterator reloc_iter = abs32_locations_.begin(); |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 110 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 111 | while (match && (reloc_iter != abs32_locations_.end())) { |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 112 | if (section_relocs_iter->r_info != R_386_RELATIVE || |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 113 | section_relocs_iter->r_offset != *reloc_iter) { |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 114 | match = false; |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 115 | } |
| 116 | ++section_relocs_iter; |
| 117 | ++reloc_iter; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | if (match) { |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 121 | // Skip over relocation tables. |
huangs | 7b221a5 | 2016-11-09 22:28:23 | [diff] [blame] | 122 | if (!receptor->EmitElfRelocation()) |
[email protected] | 811ccb2 | 2011-11-09 00:09:27 | [diff] [blame] | 123 | return false; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 124 | file_offset += sizeof(Elf32_Rel) * abs32_locations_.size(); |
| 125 | } |
| 126 | |
huangs | 7b221a5 | 2016-11-09 22:28:23 | [diff] [blame] | 127 | return ParseSimpleRegion(file_offset, section_end, receptor); |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 128 | } |
| 129 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 130 | CheckBool DisassemblerElf32X86::ParseRel32RelocsFromSection( |
| 131 | const Elf32_Shdr* section_header) { |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 132 | FileOffset start_file_offset = section_header->sh_offset; |
| 133 | FileOffset end_file_offset = start_file_offset + section_header->sh_size; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 134 | |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 135 | const uint8_t* start_pointer = FileOffsetToPointer(start_file_offset); |
| 136 | const uint8_t* end_pointer = FileOffsetToPointer(end_file_offset); |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 137 | |
| 138 | // Quick way to convert from Pointer to RVA within a single Section is to |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 139 | // subtract |pointer_to_rva|. |
avi | ab98dcc9 | 2015-12-21 19:35:33 | [diff] [blame] | 140 | const uint8_t* const adjust_pointer_to_rva = |
| 141 | start_pointer - section_header->sh_addr; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 142 | |
huangs | b1819f8 | 2016-03-31 21:51:43 | [diff] [blame] | 143 | std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); |
| 144 | |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 145 | // Find the rel32 relocations. |
avi | ab98dcc9 | 2015-12-21 19:35:33 | [diff] [blame] | 146 | const uint8_t* p = start_pointer; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 147 | while (p < end_pointer) { |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 148 | // Heuristic discovery of rel32 locations in instruction stream: are the |
| 149 | // next few bytes the start of an instruction containing a rel32 |
| 150 | // addressing mode? |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 151 | const uint8_t* rel32 = nullptr; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 152 | |
[email protected] | 17b5edc | 2011-11-09 02:15:48 | [diff] [blame] | 153 | if (p + 5 <= end_pointer) { |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 154 | if (*p == 0xE8 || *p == 0xE9) { // jmp rel32 and call rel32 |
| 155 | rel32 = p + 1; |
| 156 | } |
| 157 | } |
[email protected] | 17b5edc | 2011-11-09 02:15:48 | [diff] [blame] | 158 | if (p + 6 <= end_pointer) { |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 159 | if (*p == 0x0F && (p[1] & 0xF0) == 0x80) { // Jcc long form |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 160 | if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely |
| 161 | rel32 = p + 2; |
| 162 | } |
| 163 | } |
| 164 | if (rel32) { |
huangs | b1819f8 | 2016-03-31 21:51:43 | [diff] [blame] | 165 | RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); |
| 166 | // Is there an abs32 reloc overlapping the candidate? |
| 167 | while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3) |
| 168 | ++abs32_pos; |
| 169 | // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte |
| 170 | // region that could overlap rel32_rva. |
| 171 | if (abs32_pos != abs32_locations_.end()) { |
| 172 | if (*abs32_pos < rel32_rva + 4) { |
| 173 | // Beginning of abs32 reloc is before end of rel32 reloc so they |
| 174 | // overlap. Skip four bytes past the abs32 reloc. |
| 175 | RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); |
| 176 | p += (*abs32_pos + 4) - current_rva; |
| 177 | continue; |
| 178 | } |
| 179 | } |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 180 | |
mostynb | 1007a4a | 2016-04-11 23:18:06 | [diff] [blame] | 181 | std::unique_ptr<TypedRVAX86> typed_rel32_rva(new TypedRVAX86(rel32_rva)); |
huangs | b1819f8 | 2016-03-31 21:51:43 | [diff] [blame] | 182 | if (!typed_rel32_rva->ComputeRelativeTarget(rel32)) |
[email protected] | 144c8e9 | 2013-07-23 21:18:19 | [diff] [blame] | 183 | return false; |
[email protected] | 144c8e9 | 2013-07-23 21:18:19 | [diff] [blame] | 184 | |
huangs | b1819f8 | 2016-03-31 21:51:43 | [diff] [blame] | 185 | RVA target_rva = typed_rel32_rva->rva() + |
| 186 | typed_rel32_rva->relative_target(); |
huangs | dda11d06 | 2016-03-14 16:35:39 | [diff] [blame] | 187 | if (IsValidTargetRVA(target_rva)) { |
etiennep | 7d4e8ee | 2016-05-11 20:13:36 | [diff] [blame] | 188 | rel32_locations_.push_back(std::move(typed_rel32_rva)); |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 189 | #if COURGETTE_HISTOGRAM_TARGETS |
| 190 | ++rel32_target_rvas_[target_rva]; |
| 191 | #endif |
[email protected] | 17b5edc | 2011-11-09 02:15:48 | [diff] [blame] | 192 | p = rel32 + 4; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 193 | continue; |
[email protected] | 4b3d192b | 2011-11-08 20:32:26 | [diff] [blame] | 194 | } |
| 195 | } |
| 196 | p += 1; |
| 197 | } |
| 198 | |
| 199 | return true; |
| 200 | } |
| 201 | |
| 202 | } // namespace courgette |