Index: courgette/disassembler_elf_32.cc |
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc |
index d9d5043b2fdbae0bf5938c4675a7585509cdfeec..febcdeabef504e2c540c9d65dde763fbb093b776 100644 |
--- a/courgette/disassembler_elf_32.cc |
+++ b/courgette/disassembler_elf_32.cc |
@@ -5,6 +5,7 @@ |
#include "courgette/disassembler_elf_32.h" |
#include <algorithm> |
+#include <iterator> |
#include <utility> |
#include "base/logging.h" |
@@ -33,6 +34,15 @@ std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder( |
} // namespace |
+DisassemblerElf32::Elf32RvaVisitor_Rel32::Elf32RvaVisitor_Rel32( |
+ const std::vector<std::unique_ptr<TypedRVA>>& rva_locations) |
+ : VectorRvaVisitor<std::unique_ptr<TypedRVA>>(rva_locations) { |
+} |
+ |
+RVA DisassemblerElf32::Elf32RvaVisitor_Rel32::Get() const { |
+ return (*it_)->rva() + (*it_)->relative_target(); |
+} |
+ |
DisassemblerElf32::DisassemblerElf32(const void* start, size_t length) |
: Disassembler(start, length), |
header_(nullptr), |
@@ -164,12 +174,16 @@ bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { |
if (!ParseAbs32Relocs()) |
return false; |
- if (!ParseRel32RelocsFromSections()) |
+ if (!ParseRel32RelocsFromSections()) // Does not sort rel32 locations. |
return false; |
+ PrecomputeLabels(target); |
+ RemoveUnusedRel32Locations(target); |
+ |
if (!ParseFile(target)) |
return false; |
+ // Finally sort rel32 locations. |
std::sort(rel32_locations_.begin(), |
rel32_locations_.end(), |
TypedRVA::IsLessThanByRVA); |
@@ -180,6 +194,28 @@ bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { |
return true; |
} |
+CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const { |
+ if (rva == kUnassignedRVA) |
+ return false; |
+ |
+ // |rva| is valid if it's contained in any program segment. |
+ for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount(); |
+ ++segment_id) { |
+ const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id); |
+ |
+ if (segment_header->p_type != PT_LOAD) |
+ continue; |
+ |
+ Elf32_Addr begin = segment_header->p_vaddr; |
+ Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz; |
+ |
+ if (rva >= begin && rva < end) |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
bool DisassemblerElf32::UpdateLength() { |
Elf32_Off result = 0; |
@@ -238,32 +274,11 @@ CheckBool DisassemblerElf32::SectionName(const Elf32_Shdr& shdr, |
return true; |
} |
-CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const { |
- if (rva == kUnassignedRVA) |
- return false; |
- |
- // It's valid if it's contained in any program segment |
- for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount(); |
- ++segment_id) { |
- const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id); |
- |
- if (segment_header->p_type != PT_LOAD) |
- continue; |
- |
- Elf32_Addr begin = segment_header->p_vaddr; |
- Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz; |
- |
- if (rva >= begin && rva < end) |
- return true; |
- } |
- |
- return false; |
-} |
- |
CheckBool DisassemblerElf32::RVAsToFileOffsets( |
const std::vector<RVA>& rvas, |
std::vector<FileOffset>* file_offsets) { |
file_offsets->clear(); |
+ file_offsets->reserve(rvas.size()); |
for (RVA rva : rvas) { |
FileOffset file_offset = RVAToFileOffset(rva); |
if (file_offset == kNoFileOffset) |
@@ -284,6 +299,32 @@ CheckBool DisassemblerElf32::RVAsToFileOffsets( |
return true; |
} |
+RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() { |
+ return new RvaVisitor_Abs32(abs32_locations_, *this); |
+} |
+ |
+RvaVisitor* DisassemblerElf32::CreateRel32TargetRvaVisitor() { |
+ return new Elf32RvaVisitor_Rel32(rel32_locations_); |
+} |
+ |
+void DisassemblerElf32::RemoveUnusedRel32Locations(AssemblyProgram* program) { |
+ auto tail_it = rel32_locations_.begin(); |
+ for (auto head_it = rel32_locations_.begin(); |
+ head_it != rel32_locations_.end(); ++head_it) { |
+ RVA target_rva = (*head_it)->rva() + (*head_it)->relative_target(); |
+ if (program->FindRel32Label(target_rva) == nullptr) { |
+ // If address does not match a Label (because it was removed), deallocate. |
+ (*head_it).reset(nullptr); |
+ } else { |
+ // Else squeeze nullptr to end to compactify. |
+ if (tail_it != head_it) |
+ (*tail_it).swap(*head_it); |
+ ++tail_it; |
+ } |
+ } |
+ rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it)); |
+} |
+ |
CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) { |
// Walk all the bytes in the file, whether or not in a section. |
FileOffset file_offset = 0; |
@@ -425,7 +466,9 @@ CheckBool DisassemblerElf32::ParseProgbitsSection( |
RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset)); |
DCHECK_NE(kNoRVA, target_rva); |
- if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva))) |
+ Label* label = program->FindAbs32Label(target_rva); |
+ CHECK(label); |
+ if (!program->EmitAbs32(label)) |
return false; |
file_offset += sizeof(RVA); |
++(*current_abs_offset); |
@@ -435,12 +478,17 @@ CheckBool DisassemblerElf32::ParseProgbitsSection( |
if (*current_rel != end_rel && |
file_offset == (**current_rel)->file_offset()) { |
uint32_t relative_target = (**current_rel)->relative_target(); |
+ CHECK_EQ(RVA(origin + (file_offset - origin_offset)), |
+ (**current_rel)->rva()); |
// This cast is for 64 bit systems, and is only safe because we |
// are working on 32 bit executables. |
RVA target_rva = (RVA)(origin + (file_offset - origin_offset) + |
relative_target); |
- if (!(**current_rel)->EmitInstruction(program, target_rva)) |
+ Label* label = program->FindRel32Label(target_rva); |
+ CHECK(label); |
+ |
+ if (!(**current_rel)->EmitInstruction(program, label)) |
return false; |
file_offset += (**current_rel)->op_size(); |
++(*current_rel); |