[go: nahoru, domu]

blob: bd0623c530fa9f12d598af361ea38fecb4b9e3ec [file] [log] [blame]
Avi Drissman0ff8a7e2022-09-13 18:35:421// Copyright 2013 The Chromium Authors
paulgazz@chromium.org39ed9732013-06-20 10:17:532// 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.h"
6
7#include <algorithm>
huangsc8037632016-05-19 18:16:408#include <iterator>
paulgazz@chromium.org39ed9732013-06-20 10:17:539
Avi Drissman710fdab2023-01-11 04:37:3610#include "base/functional/bind.h"
paulgazz@chromium.org39ed9732013-06-20 10:17:5311#include "base/logging.h"
paulgazz@chromium.org39ed9732013-06-20 10:17:5312#include "courgette/assembly_program.h"
13#include "courgette/courgette.h"
paulgazz@chromium.org39ed9732013-06-20 10:17:5314
15namespace courgette {
16
huangs8cffb282016-04-09 19:43:5017namespace {
18
huangs69189302016-04-19 20:04:3319// Sorts |section_headers| by file offset and stores the resulting permutation
20// of section ids in |order|.
21std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder(
22 const std::vector<Elf32_Shdr>& section_headers) {
23 size_t size = section_headers.size();
24 std::vector<Elf32_Half> order(size);
25 for (size_t i = 0; i < size; ++i)
26 order[i] = static_cast<Elf32_Half>(i);
27
28 auto comp = [&](int idx1, int idx2) {
29 return section_headers[idx1].sh_offset < section_headers[idx2].sh_offset;
huangs8cffb282016-04-09 19:43:5030 };
huangs69189302016-04-19 20:04:3331 std::stable_sort(order.begin(), order.end(), comp);
32 return order;
huangs8cffb282016-04-09 19:43:5033}
34
35} // namespace
36
huangsc8037632016-05-19 18:16:4037DisassemblerElf32::Elf32RvaVisitor_Rel32::Elf32RvaVisitor_Rel32(
38 const std::vector<std::unique_ptr<TypedRVA>>& rva_locations)
39 : VectorRvaVisitor<std::unique_ptr<TypedRVA>>(rva_locations) {
40}
41
42RVA DisassemblerElf32::Elf32RvaVisitor_Rel32::Get() const {
43 return (*it_)->rva() + (*it_)->relative_target();
44}
45
etiennep5059bca2016-07-08 17:55:2046DisassemblerElf32::DisassemblerElf32(const uint8_t* start, size_t length)
huangsdda11d062016-03-14 16:35:3947 : Disassembler(start, length),
48 header_(nullptr),
huangsdda11d062016-03-14 16:35:3949 section_header_table_size_(0),
50 program_header_table_(nullptr),
51 program_header_table_size_(0),
etiennep5059bca2016-07-08 17:55:2052 default_string_section_(nullptr) {}
huangsdda11d062016-03-14 16:35:3953
54RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const {
55 // File offsets can be 64-bit values, but we are dealing with 32-bit
56 // executables and so only need to support 32-bit file sizes.
57 uint32_t offset32 = static_cast<uint32_t>(offset);
58
huangs69189302016-04-19 20:04:3359 // Visit section headers ordered by file offset.
60 for (Elf32_Half section_id : section_header_file_offset_order_) {
huangsdda11d062016-03-14 16:35:3961 const Elf32_Shdr* section_header = SectionHeader(section_id);
62 // These can appear to have a size in the file, but don't.
63 if (section_header->sh_type == SHT_NOBITS)
64 continue;
65
66 Elf32_Off section_begin = section_header->sh_offset;
67 Elf32_Off section_end = section_begin + section_header->sh_size;
68
69 if (offset32 >= section_begin && offset32 < section_end) {
70 return section_header->sh_addr + (offset32 - section_begin);
71 }
72 }
73
74 return 0;
75}
76
77FileOffset DisassemblerElf32::RVAToFileOffset(RVA rva) const {
78 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
79 ++section_id) {
80 const Elf32_Shdr* section_header = SectionHeader(section_id);
81 // These can appear to have a size in the file, but don't.
82 if (section_header->sh_type == SHT_NOBITS)
83 continue;
84 Elf32_Addr begin = section_header->sh_addr;
85 Elf32_Addr end = begin + section_header->sh_size;
86
87 if (rva >= begin && rva < end)
88 return section_header->sh_offset + (rva - begin);
89 }
90 return kNoFileOffset;
paulgazz@chromium.org39ed9732013-06-20 10:17:5391}
92
huangsf940a8c92016-03-23 20:40:3593RVA DisassemblerElf32::PointerToTargetRVA(const uint8_t* p) const {
94 // TODO(huangs): Add check (e.g., IsValidTargetRVA(), but more efficient).
95 return Read32LittleEndian(p);
96}
97
paulgazz@chromium.org39ed9732013-06-20 10:17:5398bool DisassemblerElf32::ParseHeader() {
99 if (length() < sizeof(Elf32_Ehdr))
100 return Bad("Too small");
101
huangsdda11d062016-03-14 16:35:39102 header_ = reinterpret_cast<const Elf32_Ehdr*>(start());
paulgazz@chromium.org39ed9732013-06-20 10:17:53103
Samuel Huang4db877c2019-03-13 20:43:30104 // Perform DisassemblerElf32::QuickDetect() checks (with error messages).
paulgazz@chromium.org39ed9732013-06-20 10:17:53105
Samuel Huang4db877c2019-03-13 20:43:30106 // Have magic for ELF header?
107 if (header_->e_ident[EI_MAG0] != 0x7F || header_->e_ident[EI_MAG1] != 'E' ||
108 header_->e_ident[EI_MAG2] != 'L' || header_->e_ident[EI_MAG3] != 'F') {
109 return Bad("No Magic Number");
110 }
111
112 if (header_->e_ident[EI_CLASS] != ELFCLASS32 ||
113 header_->e_ident[EI_DATA] != ELFDATA2LSB ||
114 header_->e_machine != ElfEM()) {
115 return Bad("Not a supported architecture");
116 }
117
118 if (header_->e_type != ET_EXEC && header_->e_type != ET_DYN)
paulgazz@chromium.org39ed9732013-06-20 10:17:53119 return Bad("Not an executable file or shared library");
120
Samuel Huang4db877c2019-03-13 20:43:30121 if (header_->e_version != 1 || header_->e_ident[EI_VERSION] != 1)
paulgazz@chromium.org39ed9732013-06-20 10:17:53122 return Bad("Unknown file version");
123
124 if (header_->e_shentsize != sizeof(Elf32_Shdr))
125 return Bad("Unexpected section header size");
126
Samuel Huang4db877c2019-03-13 20:43:30127 // Perform more complex checks, while extracting data.
128
129 if (header_->e_shoff < sizeof(Elf32_Ehdr) ||
130 !IsArrayInBounds(header_->e_shoff, header_->e_shnum,
131 sizeof(Elf32_Shdr))) {
halyavinc9de6f72015-03-24 15:40:12132 return Bad("Out of bounds section header table");
Samuel Huang4db877c2019-03-13 20:43:30133 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53134
huangs69189302016-04-19 20:04:33135 // Extract |section_header_table_|, ordered by section id.
huangs8cffb282016-04-09 19:43:50136 const Elf32_Shdr* section_header_table_raw =
137 reinterpret_cast<const Elf32_Shdr*>(
138 FileOffsetToPointer(header_->e_shoff));
paulgazz@chromium.org39ed9732013-06-20 10:17:53139 section_header_table_size_ = header_->e_shnum;
huangs69189302016-04-19 20:04:33140 section_header_table_.assign(section_header_table_raw,
141 section_header_table_raw + section_header_table_size_);
Samuel Huang4db877c2019-03-13 20:43:30142 if (!CheckSectionRanges())
143 return Bad("Out of bound section");
huangs69189302016-04-19 20:04:33144 section_header_file_offset_order_ =
145 GetSectionHeaderFileOffsetOrder(section_header_table_);
Samuel Huang4db877c2019-03-13 20:43:30146 if (header_->e_phoff < sizeof(Elf32_Ehdr) ||
147 !IsArrayInBounds(header_->e_phoff, header_->e_phnum,
148 sizeof(Elf32_Phdr))) {
halyavinc9de6f72015-03-24 15:40:12149 return Bad("Out of bounds program header table");
Samuel Huang4db877c2019-03-13 20:43:30150 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53151
Samuel Huang4db877c2019-03-13 20:43:30152 // Extract |program_header_table_|.
153 program_header_table_size_ = header_->e_phnum;
huangsdda11d062016-03-14 16:35:39154 program_header_table_ = reinterpret_cast<const Elf32_Phdr*>(
155 FileOffsetToPointer(header_->e_phoff));
Samuel Huang4db877c2019-03-13 20:43:30156 if (!CheckProgramSegmentRanges())
157 return Bad("Out of bound segment");
paulgazz@chromium.org39ed9732013-06-20 10:17:53158
Samuel Huang4db877c2019-03-13 20:43:30159 // Extract |default_string_section_|.
huangs16f01e02016-04-21 19:38:38160 Elf32_Half string_section_id = header_->e_shstrndx;
Samuel Huang4db877c2019-03-13 20:43:30161 if (string_section_id == SHN_UNDEF)
162 return Bad("Missing string section");
huangs16f01e02016-04-21 19:38:38163 if (string_section_id >= header_->e_shnum)
halyavinc9de6f72015-03-24 15:40:12164 return Bad("Out of bounds string section index");
Samuel Huang4db877c2019-03-13 20:43:30165 if (SectionHeader(string_section_id)->sh_type != SHT_STRTAB)
166 return Bad("Invalid string section");
167 default_string_section_size_ = SectionHeader(string_section_id)->sh_size;
huangs16f01e02016-04-21 19:38:38168 default_string_section_ =
169 reinterpret_cast<const char*>(SectionBody(string_section_id));
huangs16f01e02016-04-21 19:38:38170 // String section may be empty. If nonempty, then last byte must be null.
171 if (default_string_section_size_ > 0) {
172 if (default_string_section_[default_string_section_size_ - 1] != '\0')
173 return Bad("String section does not terminate");
174 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53175
Samuel Huang4db877c2019-03-13 20:43:30176 UpdateLength();
paulgazz@chromium.org39ed9732013-06-20 10:17:53177
178 return Good();
179}
180
huangsc8037632016-05-19 18:16:40181CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const {
182 if (rva == kUnassignedRVA)
183 return false;
184
185 // |rva| is valid if it's contained in any program segment.
186 for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
187 ++segment_id) {
188 const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
189
190 if (segment_header->p_type != PT_LOAD)
191 continue;
192
193 Elf32_Addr begin = segment_header->p_vaddr;
194 Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz;
195
196 if (rva >= begin && rva < end)
197 return true;
198 }
199
200 return false;
201}
202
etiennep5059bca2016-07-08 17:55:20203// static
204bool DisassemblerElf32::QuickDetect(const uint8_t* start,
205 size_t length,
206 e_machine_values elf_em) {
207 if (length < sizeof(Elf32_Ehdr))
208 return false;
209
210 const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(start);
211
212 // Have magic for ELF header?
Samuel Huang4db877c2019-03-13 20:43:30213 if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 'E' ||
214 header->e_ident[EI_MAG2] != 'L' || header->e_ident[EI_MAG3] != 'F') {
etiennep5059bca2016-07-08 17:55:20215 return false;
Samuel Huang4db877c2019-03-13 20:43:30216 }
217 if (header->e_ident[EI_CLASS] != ELFCLASS32 ||
218 header->e_ident[EI_DATA] != ELFDATA2LSB || header->e_machine != elf_em) {
219 return false;
220 }
etiennep5059bca2016-07-08 17:55:20221 if (header->e_type != ET_EXEC && header->e_type != ET_DYN)
222 return false;
Samuel Huang4db877c2019-03-13 20:43:30223 if (header->e_version != 1 || header->e_ident[EI_VERSION] != 1)
etiennep5059bca2016-07-08 17:55:20224 return false;
225 if (header->e_shentsize != sizeof(Elf32_Shdr))
226 return false;
227
228 return true;
229}
230
Samuel Huang4db877c2019-03-13 20:43:30231bool DisassemblerElf32::CheckSectionRanges() {
huangsdda11d062016-03-14 16:35:39232 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
233 ++section_id) {
234 const Elf32_Shdr* section_header = SectionHeader(section_id);
Samuel Huang4db877c2019-03-13 20:43:30235 if (section_header->sh_type == SHT_NOBITS) // E.g., .bss.
236 continue;
237 if (!IsRangeInBounds(section_header->sh_offset, section_header->sh_size))
238 return false;
239 }
240 return true;
241}
paulgazz@chromium.org39ed9732013-06-20 10:17:53242
Samuel Huang4db877c2019-03-13 20:43:30243bool DisassemblerElf32::CheckProgramSegmentRanges() {
244 for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
245 ++segment_id) {
246 const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
247 if (!IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz))
248 return false;
249 }
250 return true;
251}
252
253void DisassemblerElf32::UpdateLength() {
254 Elf32_Off result = 0;
255
256 // Find the end of the last section.
257 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
258 ++section_id) {
259 const Elf32_Shdr* section_header = SectionHeader(section_id);
paulgazz@chromium.org39ed9732013-06-20 10:17:53260 if (section_header->sh_type == SHT_NOBITS)
261 continue;
Samuel Huang4db877c2019-03-13 20:43:30262 DCHECK(IsRangeInBounds(section_header->sh_offset, section_header->sh_size));
halyavinc9de6f72015-03-24 15:40:12263 Elf32_Off section_end = section_header->sh_offset + section_header->sh_size;
264 result = std::max(result, section_end);
paulgazz@chromium.org39ed9732013-06-20 10:17:53265 }
266
Samuel Huang4db877c2019-03-13 20:43:30267 // Find the end of the last segment.
huangsdda11d062016-03-14 16:35:39268 for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
269 ++segment_id) {
270 const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
Samuel Huang4db877c2019-03-13 20:43:30271 DCHECK(IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz));
halyavinc9de6f72015-03-24 15:40:12272 Elf32_Off segment_end = segment_header->p_offset + segment_header->p_filesz;
273 result = std::max(result, segment_end);
paulgazz@chromium.org39ed9732013-06-20 10:17:53274 }
275
huangsdda11d062016-03-14 16:35:39276 Elf32_Off section_table_end =
277 header_->e_shoff + (header_->e_shnum * sizeof(Elf32_Shdr));
halyavinc9de6f72015-03-24 15:40:12278 result = std::max(result, section_table_end);
paulgazz@chromium.org39ed9732013-06-20 10:17:53279
huangsdda11d062016-03-14 16:35:39280 Elf32_Off segment_table_end =
281 header_->e_phoff + (header_->e_phnum * sizeof(Elf32_Phdr));
halyavinc9de6f72015-03-24 15:40:12282 result = std::max(result, segment_table_end);
paulgazz@chromium.org39ed9732013-06-20 10:17:53283
halyavinc9de6f72015-03-24 15:40:12284 ReduceLength(result);
paulgazz@chromium.org39ed9732013-06-20 10:17:53285}
286
huangs16f01e02016-04-21 19:38:38287CheckBool DisassemblerElf32::SectionName(const Elf32_Shdr& shdr,
288 std::string* name) const {
289 DCHECK(name);
290 size_t string_pos = shdr.sh_name;
291 if (string_pos == 0) {
292 // Empty string by convention. Valid even if string section is empty.
293 name->clear();
294 } else {
295 if (string_pos >= default_string_section_size_)
296 return false;
297 // Safe because string section must terminate with null.
298 *name = default_string_section_ + string_pos;
299 }
300 return true;
301}
302
huangsdda11d062016-03-14 16:35:39303CheckBool DisassemblerElf32::RVAsToFileOffsets(
304 const std::vector<RVA>& rvas,
huangs7b221a52016-11-09 22:28:23305 std::vector<FileOffset>* file_offsets) const {
huangsdda11d062016-03-14 16:35:39306 file_offsets->clear();
huangsc8037632016-05-19 18:16:40307 file_offsets->reserve(rvas.size());
huangsdda11d062016-03-14 16:35:39308 for (RVA rva : rvas) {
309 FileOffset file_offset = RVAToFileOffset(rva);
310 if (file_offset == kNoFileOffset)
scottmg4a95ca52016-03-12 23:54:56311 return false;
huangsdda11d062016-03-14 16:35:39312 file_offsets->push_back(file_offset);
scottmg4a95ca52016-03-12 23:54:56313 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53314 return true;
315}
316
huangsdda11d062016-03-14 16:35:39317CheckBool DisassemblerElf32::RVAsToFileOffsets(
huangs7b221a52016-11-09 22:28:23318 std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) const {
etiennep7d4e8ee2016-05-11 20:13:36319 for (auto& typed_rva : *typed_rvas) {
huangsdda11d062016-03-14 16:35:39320 FileOffset file_offset = RVAToFileOffset(typed_rva->rva());
321 if (file_offset == kNoFileOffset)
paulgazz@chromium.org144c8e92013-07-23 21:18:19322 return false;
huangsdda11d062016-03-14 16:35:39323 typed_rva->set_file_offset(file_offset);
paulgazz@chromium.org144c8e92013-07-23 21:18:19324 }
paulgazz@chromium.org144c8e92013-07-23 21:18:19325 return true;
326}
327
huangs257f9fb2017-03-23 23:17:50328bool DisassemblerElf32::ExtractAbs32Locations() {
huangsdc779d92017-03-01 22:22:38329 abs32_locations_.clear();
330
331 // Loop through sections for relocation sections
332 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
333 ++section_id) {
334 const Elf32_Shdr* section_header = SectionHeader(section_id);
335
336 if (section_header->sh_type == SHT_REL) {
337 const Elf32_Rel* relocs_table =
338 reinterpret_cast<const Elf32_Rel*>(SectionBody(section_id));
Samuel Huang59fc5662019-05-06 15:47:15339 // Reject if malformed.
340 if (section_header->sh_entsize != sizeof(Elf32_Rel))
341 return false;
342 if (section_header->sh_size % section_header->sh_entsize != 0)
343 return false;
huangsdc779d92017-03-01 22:22:38344
345 int relocs_table_count =
346 section_header->sh_size / section_header->sh_entsize;
347
348 // Elf32_Word relocation_section_id = section_header->sh_info;
349
350 // Loop through relocation objects in the relocation section
351 for (int rel_id = 0; rel_id < relocs_table_count; ++rel_id) {
352 RVA rva;
353
354 // Quite a few of these conversions fail, and we simply skip
355 // them, that's okay.
356 if (RelToRVA(relocs_table[rel_id], &rva) && CheckSection(rva))
357 abs32_locations_.push_back(rva);
358 }
359 }
360 }
361
362 std::sort(abs32_locations_.begin(), abs32_locations_.end());
363 DCHECK(abs32_locations_.empty() || abs32_locations_.back() != kUnassignedRVA);
364 return true;
365}
366
huangs257f9fb2017-03-23 23:17:50367bool DisassemblerElf32::ExtractRel32Locations() {
huangsdc779d92017-03-01 22:22:38368 rel32_locations_.clear();
369 bool found_rel32 = false;
370
371 // Loop through sections for relocation sections
372 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
373 ++section_id) {
374 const Elf32_Shdr* section_header = SectionHeader(section_id);
375
376 // Some debug sections can have sh_type=SHT_PROGBITS but sh_addr=0.
377 if (section_header->sh_type != SHT_PROGBITS || section_header->sh_addr == 0)
378 continue;
379
380 // Heuristic: Only consider ".text" section.
381 std::string section_name;
382 if (!SectionName(*section_header, &section_name))
383 return false;
384 if (section_name != ".text")
385 continue;
386
387 found_rel32 = true;
388 if (!ParseRel32RelocsFromSection(section_header))
389 return false;
390 }
391 if (!found_rel32)
392 VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?";
393
huangsc615c9112017-03-22 06:52:24394 std::sort(rel32_locations_.begin(), rel32_locations_.end(),
395 TypedRVA::IsLessThanByRVA);
396 DCHECK(rel32_locations_.empty() ||
397 rel32_locations_.back()->rva() != kUnassignedRVA);
398
huangsdc779d92017-03-01 22:22:38399 return true;
400}
401
huangsc8037632016-05-19 18:16:40402RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() {
403 return new RvaVisitor_Abs32(abs32_locations_, *this);
404}
405
406RvaVisitor* DisassemblerElf32::CreateRel32TargetRvaVisitor() {
407 return new Elf32RvaVisitor_Rel32(rel32_locations_);
408}
409
410void DisassemblerElf32::RemoveUnusedRel32Locations(AssemblyProgram* program) {
411 auto tail_it = rel32_locations_.begin();
412 for (auto head_it = rel32_locations_.begin();
413 head_it != rel32_locations_.end(); ++head_it) {
414 RVA target_rva = (*head_it)->rva() + (*head_it)->relative_target();
415 if (program->FindRel32Label(target_rva) == nullptr) {
416 // If address does not match a Label (because it was removed), deallocate.
417 (*head_it).reset(nullptr);
418 } else {
419 // Else squeeze nullptr to end to compactify.
420 if (tail_it != head_it)
421 (*tail_it).swap(*head_it);
422 ++tail_it;
423 }
424 }
425 rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it));
426}
427
huangs257f9fb2017-03-23 23:17:50428InstructionGenerator DisassemblerElf32::GetInstructionGenerator(
429 AssemblyProgram* program) {
tzik0881a4002018-03-08 06:19:49430 return base::BindRepeating(&DisassemblerElf32::ParseFile,
431 base::Unretained(this), program);
huangs257f9fb2017-03-23 23:17:50432}
433
huangs7b221a52016-11-09 22:28:23434CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program,
435 InstructionReceptor* receptor) const {
paulgazz@chromium.org39ed9732013-06-20 10:17:53436 // Walk all the bytes in the file, whether or not in a section.
huangsdda11d062016-03-14 16:35:39437 FileOffset file_offset = 0;
paulgazz@chromium.org39ed9732013-06-20 10:17:53438
huangs3da0dd932016-04-28 22:14:45439 // File parsing follows file offset order, and we visit abs32 and rel32
440 // locations in lockstep. Therefore we need to extract and sort file offsets
huangsc615c9112017-03-22 06:52:24441 // of all abs32 and rel32 locations. For abs32, we copy the offsets to a new
442 // array.
443 std::vector<FileOffset> abs_offsets;
huangsdda11d062016-03-14 16:35:39444 if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets))
paulgazz@chromium.org39ed9732013-06-20 10:17:53445 return false;
huangsc615c9112017-03-22 06:52:24446 std::sort(abs_offsets.begin(), abs_offsets.end());
paulgazz@chromium.org39ed9732013-06-20 10:17:53447
huangsc615c9112017-03-22 06:52:24448 // For rel32, TypedRVA (rather than raw offset) is stored, so sort-by-offset
449 // is performed in place to save memory. At the end of function we will
450 // sort-by-RVA.
huangsdda11d062016-03-14 16:35:39451 if (!RVAsToFileOffsets(&rel32_locations_))
paulgazz@chromium.org39ed9732013-06-20 10:17:53452 return false;
huangs3da0dd932016-04-28 22:14:45453 std::sort(rel32_locations_.begin(),
454 rel32_locations_.end(),
455 TypedRVA::IsLessThanByFileOffset);
paulgazz@chromium.org39ed9732013-06-20 10:17:53456
huangsdda11d062016-03-14 16:35:39457 std::vector<FileOffset>::iterator current_abs_offset = abs_offsets.begin();
huangsdda11d062016-03-14 16:35:39458 std::vector<FileOffset>::iterator end_abs_offset = abs_offsets.end();
huangs3da0dd932016-04-28 22:14:45459
etiennep7d4e8ee2016-05-11 20:13:36460 std::vector<std::unique_ptr<TypedRVA>>::iterator current_rel =
461 rel32_locations_.begin();
462 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel =
463 rel32_locations_.end();
paulgazz@chromium.org39ed9732013-06-20 10:17:53464
huangs69189302016-04-19 20:04:33465 // Visit section headers ordered by file offset.
466 for (Elf32_Half section_id : section_header_file_offset_order_) {
huangsdda11d062016-03-14 16:35:39467 const Elf32_Shdr* section_header = SectionHeader(section_id);
paulgazz@chromium.org39ed9732013-06-20 10:17:53468
Will Harris3e6fa972015-03-02 21:14:25469 if (section_header->sh_type == SHT_NOBITS)
470 continue;
471
huangs7b221a52016-11-09 22:28:23472 if (!ParseSimpleRegion(file_offset, section_header->sh_offset, receptor))
paulgazz@chromium.org39ed9732013-06-20 10:17:53473 return false;
huangsdda11d062016-03-14 16:35:39474
paulgazz@chromium.org39ed9732013-06-20 10:17:53475 file_offset = section_header->sh_offset;
476
477 switch (section_header->sh_type) {
478 case SHT_REL:
huangs7b221a52016-11-09 22:28:23479 if (!ParseRelocationSection(section_header, receptor))
paulgazz@chromium.org39ed9732013-06-20 10:17:53480 return false;
481 file_offset = section_header->sh_offset + section_header->sh_size;
482 break;
483 case SHT_PROGBITS:
huangs7b221a52016-11-09 22:28:23484 if (!ParseProgbitsSection(section_header, &current_abs_offset,
485 end_abs_offset, &current_rel, end_rel,
486 program, receptor)) {
paulgazz@chromium.org39ed9732013-06-20 10:17:53487 return false;
huangsdda11d062016-03-14 16:35:39488 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53489 file_offset = section_header->sh_offset + section_header->sh_size;
490 break;
paulgazz@chromium.org39ed9732013-06-20 10:17:53491 case SHT_INIT_ARRAY:
492 // Fall through
493 case SHT_FINI_ARRAY:
494 while (current_abs_offset != end_abs_offset &&
495 *current_abs_offset >= section_header->sh_offset &&
496 *current_abs_offset <
huangsdda11d062016-03-14 16:35:39497 section_header->sh_offset + section_header->sh_size) {
paulgazz@chromium.org39ed9732013-06-20 10:17:53498 // Skip any abs_offsets appear in the unsupported INIT_ARRAY section
huangsdda11d062016-03-14 16:35:39499 VLOG(1) << "Skipping relocation entry for unsupported section: "
500 << section_header->sh_type;
501 ++current_abs_offset;
paulgazz@chromium.org39ed9732013-06-20 10:17:53502 }
503 break;
504 default:
505 if (current_abs_offset != end_abs_offset &&
huangsdda11d062016-03-14 16:35:39506 *current_abs_offset >= section_header->sh_offset &&
507 *current_abs_offset <
508 section_header->sh_offset + section_header->sh_size) {
509 VLOG(1) << "Relocation address in unrecognized ELF section: "
510 << section_header->sh_type;
511 }
512 break;
paulgazz@chromium.org39ed9732013-06-20 10:17:53513 }
514 }
515
516 // Rest of the file past the last section
huangs7b221a52016-11-09 22:28:23517 if (!ParseSimpleRegion(file_offset, length(), receptor))
paulgazz@chromium.org39ed9732013-06-20 10:17:53518 return false;
519
huangsc615c9112017-03-22 06:52:24520 // Restore original rel32 location order and sort by RVA order.
521 std::sort(rel32_locations_.begin(), rel32_locations_.end(),
522 TypedRVA::IsLessThanByRVA);
523
paulgazz@chromium.org39ed9732013-06-20 10:17:53524 // Make certain we consume all of the relocations as expected
525 return (current_abs_offset == end_abs_offset);
526}
527
528CheckBool DisassemblerElf32::ParseProgbitsSection(
huangsdda11d062016-03-14 16:35:39529 const Elf32_Shdr* section_header,
530 std::vector<FileOffset>::iterator* current_abs_offset,
531 std::vector<FileOffset>::iterator end_abs_offset,
etiennep7d4e8ee2016-05-11 20:13:36532 std::vector<std::unique_ptr<TypedRVA>>::iterator* current_rel,
533 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel,
huangs7b221a52016-11-09 22:28:23534 AssemblyProgram* program,
535 InstructionReceptor* receptor) const {
paulgazz@chromium.org39ed9732013-06-20 10:17:53536 // Walk all the bytes in the file, whether or not in a section.
huangsdda11d062016-03-14 16:35:39537 FileOffset file_offset = section_header->sh_offset;
538 FileOffset section_end = section_header->sh_offset + section_header->sh_size;
paulgazz@chromium.org39ed9732013-06-20 10:17:53539
540 Elf32_Addr origin = section_header->sh_addr;
huangsdda11d062016-03-14 16:35:39541 FileOffset origin_offset = section_header->sh_offset;
huangs7b221a52016-11-09 22:28:23542 if (!receptor->EmitOrigin(origin))
paulgazz@chromium.org39ed9732013-06-20 10:17:53543 return false;
544
545 while (file_offset < section_end) {
paulgazz@chromium.org39ed9732013-06-20 10:17:53546 if (*current_abs_offset != end_abs_offset &&
547 file_offset > **current_abs_offset)
548 return false;
549
paulgazz@chromium.org144c8e92013-07-23 21:18:19550 while (*current_rel != end_rel &&
huangsdda11d062016-03-14 16:35:39551 file_offset > (**current_rel)->file_offset()) {
552 ++(*current_rel);
paulgazz@chromium.org39ed9732013-06-20 10:17:53553 }
554
huangsdda11d062016-03-14 16:35:39555 FileOffset next_relocation = section_end;
paulgazz@chromium.org39ed9732013-06-20 10:17:53556
557 if (*current_abs_offset != end_abs_offset &&
558 next_relocation > **current_abs_offset)
559 next_relocation = **current_abs_offset;
560
561 // Rel offsets are heuristically derived, and might (incorrectly) overlap
562 // an Abs value, or the end of the section, so +3 to make sure there is
563 // room for the full 4 byte value.
paulgazz@chromium.org144c8e92013-07-23 21:18:19564 if (*current_rel != end_rel &&
huangsdda11d062016-03-14 16:35:39565 next_relocation > ((**current_rel)->file_offset() + 3))
566 next_relocation = (**current_rel)->file_offset();
paulgazz@chromium.org39ed9732013-06-20 10:17:53567
568 if (next_relocation > file_offset) {
huangs7b221a52016-11-09 22:28:23569 if (!ParseSimpleRegion(file_offset, next_relocation, receptor))
paulgazz@chromium.org39ed9732013-06-20 10:17:53570 return false;
571
572 file_offset = next_relocation;
573 continue;
574 }
575
576 if (*current_abs_offset != end_abs_offset &&
577 file_offset == **current_abs_offset) {
huangsf940a8c92016-03-23 20:40:35578 RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset));
579 DCHECK_NE(kNoRVA, target_rva);
paulgazz@chromium.org39ed9732013-06-20 10:17:53580
huangsc8037632016-05-19 18:16:40581 Label* label = program->FindAbs32Label(target_rva);
582 CHECK(label);
huangs7b221a52016-11-09 22:28:23583 if (!receptor->EmitAbs32(label))
paulgazz@chromium.org39ed9732013-06-20 10:17:53584 return false;
585 file_offset += sizeof(RVA);
huangsdda11d062016-03-14 16:35:39586 ++(*current_abs_offset);
paulgazz@chromium.org39ed9732013-06-20 10:17:53587 continue;
588 }
589
paulgazz@chromium.org144c8e92013-07-23 21:18:19590 if (*current_rel != end_rel &&
huangsdda11d062016-03-14 16:35:39591 file_offset == (**current_rel)->file_offset()) {
aviab98dcc92015-12-21 19:35:33592 uint32_t relative_target = (**current_rel)->relative_target();
huangsc8037632016-05-19 18:16:40593 CHECK_EQ(RVA(origin + (file_offset - origin_offset)),
594 (**current_rel)->rva());
paulgazz@chromium.org39ed9732013-06-20 10:17:53595 // This cast is for 64 bit systems, and is only safe because we
596 // are working on 32 bit executables.
597 RVA target_rva = (RVA)(origin + (file_offset - origin_offset) +
paulgazz@chromium.org144c8e92013-07-23 21:18:19598 relative_target);
paulgazz@chromium.org39ed9732013-06-20 10:17:53599
huangsc8037632016-05-19 18:16:40600 Label* label = program->FindRel32Label(target_rva);
601 CHECK(label);
602
huangs7b221a52016-11-09 22:28:23603 if (!(**current_rel)->EmitInstruction(label, receptor))
paulgazz@chromium.org39ed9732013-06-20 10:17:53604 return false;
paulgazz@chromium.org2b637b62013-08-01 00:11:24605 file_offset += (**current_rel)->op_size();
huangsdda11d062016-03-14 16:35:39606 ++(*current_rel);
paulgazz@chromium.org39ed9732013-06-20 10:17:53607 continue;
608 }
609 }
610
611 // Rest of the section (if any)
huangs7b221a52016-11-09 22:28:23612 return ParseSimpleRegion(file_offset, section_end, receptor);
paulgazz@chromium.org39ed9732013-06-20 10:17:53613}
614
huangs7b221a52016-11-09 22:28:23615CheckBool DisassemblerElf32::ParseSimpleRegion(
616 FileOffset start_file_offset,
617 FileOffset end_file_offset,
618 InstructionReceptor* receptor) const {
paulgazz@chromium.orgc092858a2013-08-13 00:46:30619 // Callers don't guarantee start < end
huangsdda11d062016-03-14 16:35:39620 if (start_file_offset >= end_file_offset)
621 return true;
paulgazz@chromium.org39ed9732013-06-20 10:17:53622
pkasting8e3a26a2014-10-03 18:52:29623 const size_t len = end_file_offset - start_file_offset;
paulgazz@chromium.orgc092858a2013-08-13 00:46:30624
huangs7b221a52016-11-09 22:28:23625 if (!receptor->EmitMultipleBytes(FileOffsetToPointer(start_file_offset),
626 len)) {
paulgazz@chromium.orgc092858a2013-08-13 00:46:30627 return false;
huangsdda11d062016-03-14 16:35:39628 }
paulgazz@chromium.org39ed9732013-06-20 10:17:53629
630 return true;
631}
632
paulgazz@chromium.orga8e80412013-07-18 22:07:53633CheckBool DisassemblerElf32::CheckSection(RVA rva) {
Samuel Huang49bd5efa82020-04-22 19:22:59634 // Handle 32-bit references only.
635 constexpr uint8_t kWidth = 4;
636
huangsdda11d062016-03-14 16:35:39637 FileOffset file_offset = RVAToFileOffset(rva);
638 if (file_offset == kNoFileOffset)
paulgazz@chromium.orga8e80412013-07-18 22:07:53639 return false;
paulgazz@chromium.orga8e80412013-07-18 22:07:53640
huangsdda11d062016-03-14 16:35:39641 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
642 ++section_id) {
643 const Elf32_Shdr* section_header = SectionHeader(section_id);
Samuel Huang49bd5efa82020-04-22 19:22:59644 // Take account of pointer |kWidth|, and reject pointers that start within
645 // the section but whose span lies outside.
646 FileOffset start_offset = section_header->sh_offset;
647 if (file_offset < start_offset || section_header->sh_size < kWidth)
648 continue;
649 FileOffset end_offset = start_offset + section_header->sh_size - kWidth + 1;
650 if (file_offset >= end_offset)
651 continue;
paulgazz@chromium.orga8e80412013-07-18 22:07:53652
Samuel Huang49bd5efa82020-04-22 19:22:59653 switch (section_header->sh_type) {
654 case SHT_REL: // Falls through.
655 case SHT_PROGBITS:
656 return true;
paulgazz@chromium.orga8e80412013-07-18 22:07:53657 }
658 }
659
660 return false;
661}
662
paulgazz@chromium.org39ed9732013-06-20 10:17:53663} // namespace courgette