diff options
author | paulgazz@chromium.org <paulgazz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 10:17:53 +0000 |
---|---|---|
committer | paulgazz@chromium.org <paulgazz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 10:17:53 +0000 |
commit | 39ed97339553d0d2ba201b225afd4eed460f744b (patch) | |
tree | 3817f40021a7d39d6800c98f95486d8e5d1b7a1c /courgette | |
parent | 6edd61cce39b3778765af46627ef235551370077 (diff) | |
download | chromium_src-39ed97339553d0d2ba201b225afd4eed460f744b.zip chromium_src-39ed97339553d0d2ba201b225afd4eed460f744b.tar.gz chromium_src-39ed97339553d0d2ba201b225afd4eed460f744b.tar.bz2 |
Factored out common ELF processing into a common superclass, an x86 subclass, and an initial ARM subclass.
Created a new disassembler virtual class, DisassemblerElf32, that
implements the common functions for processing ELF 32-bit files. This
class is defined in disassembler_elf_32.{h|cc}, and has nearly all of
the methods and data that used to be in
disassembler_elf_32_x86.{h|cc}. This class has two subclasses, one
for x86 and one for arm, which implement the architecture-specific
parts for generating courgette patches, namely extracting relative and
absolute addresses. The ARM subclass is just a shell, but still
yields correct courgette patches.
The rest of the files add new enums for ARM and use the ARM subclasses
for the courgette command-line tool.
BUG=
Review URL: https://chromiumcodereview.appspot.com/17325003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207388 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'courgette')
-rw-r--r-- | courgette/courgette.gyp | 4 | ||||
-rw-r--r-- | courgette/courgette.h | 1 | ||||
-rw-r--r-- | courgette/courgette_tool.cc | 5 | ||||
-rw-r--r-- | courgette/disassembler.cc | 7 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.cc | 462 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.h | 154 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_arm.cc | 111 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_arm.h | 42 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_x86.cc | 440 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_x86.h | 115 | ||||
-rw-r--r-- | courgette/ensemble_apply.cc | 3 | ||||
-rw-r--r-- | courgette/ensemble_create.cc | 9 | ||||
-rw-r--r-- | courgette/types_elf.h | 5 |
13 files changed, 811 insertions, 547 deletions
diff --git a/courgette/courgette.gyp b/courgette/courgette.gyp index 1d6c030..f4d0365 100644 --- a/courgette/courgette.gyp +++ b/courgette/courgette.gyp @@ -22,6 +22,10 @@ 'difference_estimator.h', 'disassembler.cc', 'disassembler.h', + 'disassembler_elf_32.cc', + 'disassembler_elf_32.h', + 'disassembler_elf_32_arm.cc', + 'disassembler_elf_32_arm.h', 'disassembler_elf_32_x86.cc', 'disassembler_elf_32_x86.h', 'disassembler_win32_x86.cc', diff --git a/courgette/courgette.h b/courgette/courgette.h index 91b9038..4831228 100644 --- a/courgette/courgette.h +++ b/courgette/courgette.h @@ -56,6 +56,7 @@ enum ExecutableType { EXE_UNKNOWN = 0, EXE_WIN_32_X86 = 1, EXE_ELF_32_X86 = 2, + EXE_ELF_32_ARM = 3, }; class SinkStream; diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc index 523cc4d..6aa951a 100644 --- a/courgette/courgette_tool.cc +++ b/courgette/courgette_tool.cc @@ -135,6 +135,11 @@ bool Supported(const base::FilePath& input_file) { format = "ELF 32 X86"; result = true; break; + + case courgette::EXE_ELF_32_ARM: + format = "ELF 32 ARM"; + result = true; + break; } printf("%s Executable\n", format.c_str()); diff --git a/courgette/disassembler.cc b/courgette/disassembler.cc index 103bbe0..48227b3 100644 --- a/courgette/disassembler.cc +++ b/courgette/disassembler.cc @@ -13,6 +13,7 @@ #include "courgette/assembly_program.h" #include "courgette/courgette.h" +#include "courgette/disassembler_elf_32_arm.h" #include "courgette/disassembler_elf_32_x86.h" #include "courgette/disassembler_win32_x86.h" #include "courgette/encoded_program.h" @@ -40,6 +41,12 @@ Disassembler* DetectDisassembler(const void* buffer, size_t length) { else delete disassembler; + disassembler = new DisassemblerElf32ARM(buffer, length); + if (disassembler->ParseHeader()) + return disassembler; + else + delete disassembler; + return NULL; } diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc new file mode 100644 index 0000000..bd49ff1 --- /dev/null +++ b/courgette/disassembler_elf_32.cc @@ -0,0 +1,462 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "courgette/disassembler_elf_32.h" + +#include <algorithm> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" + +#include "courgette/assembly_program.h" +#include "courgette/courgette.h" +#include "courgette/encoded_program.h" + +namespace courgette { + +DisassemblerElf32::DisassemblerElf32(const void* start, size_t length) + : Disassembler(start, length), + header_(NULL), + section_header_table_(NULL), + section_header_table_size_(0), + program_header_table_(NULL), + program_header_table_size_(0), + default_string_section_(NULL) { +} + +bool DisassemblerElf32::ParseHeader() { + if (length() < sizeof(Elf32_Ehdr)) + return Bad("Too small"); + + header_ = (Elf32_Ehdr *)start(); + + // Have magic for elf header? + if (header_->e_ident[0] != 0x7f || + header_->e_ident[1] != 'E' || + header_->e_ident[2] != 'L' || + header_->e_ident[3] != 'F') + return Bad("No Magic Number"); + + if (header_->e_type != ET_EXEC && + header_->e_type != ET_DYN) + return Bad("Not an executable file or shared library"); + + if (header_->e_machine != ElfEM()) + return Bad("Not a supported architecture"); + + if (header_->e_version != 1) + return Bad("Unknown file version"); + + if (header_->e_shentsize != sizeof(Elf32_Shdr)) + return Bad("Unexpected section header size"); + + if (header_->e_shoff >= length()) + return Bad("Out of bounds section header table offset"); + + section_header_table_ = (Elf32_Shdr *)OffsetToPointer(header_->e_shoff); + section_header_table_size_ = header_->e_shnum; + + if ((header_->e_shoff + header_->e_shnum ) >= length()) + return Bad("Out of bounds section header table"); + + if (header_->e_phoff >= length()) + return Bad("Out of bounds program header table offset"); + + program_header_table_ = (Elf32_Phdr *)OffsetToPointer(header_->e_phoff); + program_header_table_size_ = header_->e_phnum; + + if ((header_->e_phoff + header_->e_phnum) >= length()) + return Bad("Out of bounds program header table"); + + default_string_section_ = (const char *)SectionBody((int)header_->e_shstrndx); + + ReduceLength(DiscoverLength()); + + return Good(); +} + +bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { + if (!ok()) + return false; + + // The Image Base is always 0 for ELF Executables + target->set_image_base(0); + + if (!ParseAbs32Relocs()) + return false; + + if (!ParseRel32RelocsFromSections()) + return false; + + if (!ParseFile(target)) + return false; + + target->DefaultAssignIndexes(); + + return true; +} + +uint32 DisassemblerElf32::DiscoverLength() { + uint32 result = 0; + + // Find the end of the last section + for (int section_id = 0; section_id < SectionHeaderCount(); section_id++) { + const Elf32_Shdr *section_header = SectionHeader(section_id); + + if (section_header->sh_type == SHT_NOBITS) + continue; + + uint32 section_end = section_header->sh_offset + section_header->sh_size; + + if (section_end > result) + result = section_end; + } + + // Find the end of the last segment + for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { + const Elf32_Phdr *segment_header = ProgramSegmentHeader(i); + + uint32 segment_end = segment_header->p_offset + segment_header->p_filesz; + + if (segment_end > result) + result = segment_end; + } + + uint32 section_table_end = header_->e_shoff + + (header_->e_shnum * sizeof(Elf32_Shdr)); + if (section_table_end > result) + result = section_table_end; + + uint32 segment_table_end = header_->e_phoff + + (header_->e_phnum * sizeof(Elf32_Phdr)); + if (segment_table_end > result) + result = segment_table_end; + + return result; +} + +CheckBool DisassemblerElf32::IsValidRVA(RVA rva) const { + + // It's valid if it's contained in any program segment + for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { + const Elf32_Phdr *segment_header = ProgramSegmentHeader(i); + + 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; +} + +// Returns RVA for an in memory address, or NULL. +CheckBool DisassemblerElf32::RVAToFileOffset(Elf32_Addr addr, + size_t* result) const { + + for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { + Elf32_Addr begin = ProgramSegmentMemoryBegin(i); + Elf32_Addr end = begin + ProgramSegmentMemorySize(i); + + if (addr >= begin && addr < end) { + Elf32_Addr offset = addr - begin; + + if (offset < ProgramSegmentFileSize(i)) { + *result = ProgramSegmentFileOffset(i) + offset; + return true; + } + } + } + + return false; +} + +RVA DisassemblerElf32::FileOffsetToRVA(size_t offset) const { + // File offsets can be 64 bit values, but we are dealing with 32 + // bit executables and so only need to support 32bit file sizes. + uint32 offset32 = (uint32)offset; + + for (int i = 0; i < SectionHeaderCount(); i++) { + + const Elf32_Shdr *section_header = SectionHeader(i); + + // These can appear to have a size in the file, but don't. + if (section_header->sh_type == SHT_NOBITS) + continue; + + Elf32_Off section_begin = section_header->sh_offset; + Elf32_Off section_end = section_begin + section_header->sh_size; + + if (offset32 >= section_begin && offset32 < section_end) { + return section_header->sh_addr + (offset32 - section_begin); + } + } + + return 0; +} + +CheckBool DisassemblerElf32::RVAsToOffsets(std::vector<RVA>* rvas, + std::vector<size_t>* offsets) { + offsets->clear(); + + for (std::vector<RVA>::iterator rva = rvas->begin(); + rva != rvas->end(); + rva++) { + + size_t offset; + + if (!RVAToFileOffset(*rva, &offset)) + return false; + + offsets->push_back(offset); + } + + return true; +} + +CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) { + // Walk all the bytes in the file, whether or not in a section. + uint32 file_offset = 0; + + std::vector<size_t> abs_offsets; + std::vector<size_t> rel_offsets; + + if (!RVAsToOffsets(&abs32_locations_, &abs_offsets)) + return false; + + if (!RVAsToOffsets(&rel32_locations_, &rel_offsets)) + return false; + + std::vector<size_t>::iterator current_abs_offset = abs_offsets.begin(); + std::vector<size_t>::iterator current_rel_offset = rel_offsets.begin(); + + std::vector<size_t>::iterator end_abs_offset = abs_offsets.end(); + std::vector<size_t>::iterator end_rel_offset = rel_offsets.end(); + + for (int section_id = 0; + section_id < SectionHeaderCount(); + section_id++) { + + const Elf32_Shdr *section_header = SectionHeader(section_id); + + if (!ParseSimpleRegion(file_offset, + section_header->sh_offset, + program)) + return false; + file_offset = section_header->sh_offset; + + switch (section_header->sh_type) { + case SHT_REL: + if (!ParseRelocationSection(section_header, program)) + return false; + file_offset = section_header->sh_offset + section_header->sh_size; + break; + case SHT_PROGBITS: + if (!ParseProgbitsSection(section_header, + ¤t_abs_offset, end_abs_offset, + ¤t_rel_offset, end_rel_offset, + program)) + return false; + file_offset = section_header->sh_offset + section_header->sh_size; + break; + case SHT_NOBITS: + // Fall through + case SHT_INIT_ARRAY: + // Fall through + case SHT_FINI_ARRAY: + while (current_abs_offset != end_abs_offset && + *current_abs_offset >= section_header->sh_offset && + *current_abs_offset < + (section_header->sh_offset + section_header->sh_size)) { + // Skip any abs_offsets appear in the unsupported INIT_ARRAY section + VLOG(1) << "Skipping relocation entry for unsupported section: " << + section_header->sh_type; + current_abs_offset++; + } + break; + default: + if (current_abs_offset != end_abs_offset && + *current_abs_offset >= section_header->sh_offset && + *current_abs_offset < + (section_header->sh_offset + section_header->sh_size)) + VLOG(1) << "Relocation address in unrecognized ELF section: " << \ + section_header->sh_type; + break; + } + } + + // Rest of the file past the last section + if (!ParseSimpleRegion(file_offset, + length(), + program)) + return false; + + // Make certain we consume all of the relocations as expected + return (current_abs_offset == end_abs_offset); +} + +CheckBool DisassemblerElf32::ParseProgbitsSection( + const Elf32_Shdr *section_header, + std::vector<size_t>::iterator* current_abs_offset, + std::vector<size_t>::iterator end_abs_offset, + std::vector<size_t>::iterator* current_rel_offset, + std::vector<size_t>::iterator end_rel_offset, + AssemblyProgram* program) { + + // Walk all the bytes in the file, whether or not in a section. + size_t file_offset = section_header->sh_offset; + size_t section_end = section_header->sh_offset + section_header->sh_size; + + Elf32_Addr origin = section_header->sh_addr; + size_t origin_offset = section_header->sh_offset; + if (!program->EmitOriginInstruction(origin)) + return false; + + while (file_offset < section_end) { + + if (*current_abs_offset != end_abs_offset && + file_offset > **current_abs_offset) + return false; + + while (*current_rel_offset != end_rel_offset && + file_offset > **current_rel_offset) { + (*current_rel_offset)++; + } + + size_t next_relocation = section_end; + + if (*current_abs_offset != end_abs_offset && + next_relocation > **current_abs_offset) + next_relocation = **current_abs_offset; + + // Rel offsets are heuristically derived, and might (incorrectly) overlap + // an Abs value, or the end of the section, so +3 to make sure there is + // room for the full 4 byte value. + if (*current_rel_offset != end_rel_offset && + next_relocation > (**current_rel_offset + 3)) + next_relocation = **current_rel_offset; + + if (next_relocation > file_offset) { + if (!ParseSimpleRegion(file_offset, next_relocation, program)) + return false; + + file_offset = next_relocation; + continue; + } + + if (*current_abs_offset != end_abs_offset && + file_offset == **current_abs_offset) { + + const uint8* p = OffsetToPointer(file_offset); + RVA target_rva = Read32LittleEndian(p); + + if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva))) + return false; + file_offset += sizeof(RVA); + (*current_abs_offset)++; + continue; + } + + if (*current_rel_offset != end_rel_offset && + file_offset == **current_rel_offset) { + + const uint8* p = OffsetToPointer(file_offset); + uint32 relative_target = Read32LittleEndian(p); + // 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) + + 4 + relative_target); + + if (!program->EmitRel32(program->FindOrMakeRel32Label(target_rva))) + return false; + file_offset += sizeof(RVA); + (*current_rel_offset)++; + continue; + } + } + + // Rest of the section (if any) + return ParseSimpleRegion(file_offset, section_end, program); +} + +CheckBool DisassemblerElf32::ParseSimpleRegion( + size_t start_file_offset, + size_t end_file_offset, + AssemblyProgram* program) { + + const uint8* start = OffsetToPointer(start_file_offset); + const uint8* end = OffsetToPointer(end_file_offset); + + const uint8* p = start; + + while (p < end) { + if (!program->EmitByteInstruction(*p)) + return false; + ++p; + } + + return true; +} + +CheckBool DisassemblerElf32::ParseAbs32Relocs() { + abs32_locations_.clear(); + + // Loop through sections for relocation sections + for (int section_id = 0; section_id < SectionHeaderCount(); section_id++) { + const Elf32_Shdr *section_header = SectionHeader(section_id); + + if (section_header->sh_type == SHT_REL) { + + Elf32_Rel *relocs_table = (Elf32_Rel *)SectionBody(section_id); + + int relocs_table_count = section_header->sh_size / + section_header->sh_entsize; + + // Elf32_Word relocation_section_id = section_header->sh_info; + + // Loop through relocation objects in the relocation section + for (int rel_id = 0; rel_id < relocs_table_count; rel_id++) { + RVA rva; + + // Quite a few of these conversions fail, and we simply skip + // them, that's okay. + if (RelToRVA(relocs_table[rel_id], &rva)) + abs32_locations_.push_back(rva); + } + } + } + + std::sort(abs32_locations_.begin(), abs32_locations_.end()); + return true; +} + +CheckBool DisassemblerElf32::ParseRel32RelocsFromSections() { + + rel32_locations_.clear(); + + // Loop through sections for relocation sections + for (int section_id = 0; + section_id < SectionHeaderCount(); + section_id++) { + + const Elf32_Shdr *section_header = SectionHeader(section_id); + + if (section_header->sh_type != SHT_PROGBITS) + continue; + + if (!ParseRel32RelocsFromSection(section_header)) + return false; + } + + std::sort(rel32_locations_.begin(), rel32_locations_.end()); + return true; +} + +} // namespace courgette diff --git a/courgette/disassembler_elf_32.h b/courgette/disassembler_elf_32.h new file mode 100644 index 0000000..5c3f8a2 --- /dev/null +++ b/courgette/disassembler_elf_32.h @@ -0,0 +1,154 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COURGETTE_DISASSEMBLER_ELF_32_H_ +#define COURGETTE_DISASSEMBLER_ELF_32_H_ + +#include "base/basictypes.h" +#include "courgette/disassembler.h" +#include "courgette/memory_allocator.h" +#include "courgette/types_elf.h" + +namespace courgette { + +class AssemblyProgram; + +// A courgette disassembler for 32-bit ELF files. This class is only a +// partial implementation. Subclasses implement the +// architecture-specific parts of processing 32-bit ELF files. Specifically, +// RelToRVA processes entries in ELF relocation table, +// ParseRelocationSection verifies the organization of the ELF +// relocation table, and ParseRel32RelocsFromSection finds branch +// targets by looking for relative jump/call opcodes in the particular +// architecture's machine code. +class DisassemblerElf32 : public Disassembler { + public: + explicit DisassemblerElf32(const void* start, size_t length); + + virtual ExecutableType kind() = 0; + + virtual e_machine_values ElfEM() = 0; + + // Returns 'true' if the buffer appears to point to a valid ELF executable + // for 32 bit. If ParseHeader() succeeds, other member + // functions may be called. + virtual bool ParseHeader(); + + virtual bool Disassemble(AssemblyProgram* target); + + // Public for unittests only + std::vector<RVA> &Abs32Locations() { return abs32_locations_; } + std::vector<RVA> &Rel32Locations() { return rel32_locations_; } + + protected: + + uint32 DiscoverLength(); + + // Misc Section Helpers + + const Elf32_Half SectionHeaderCount() const { + return section_header_table_size_; + } + + const Elf32_Shdr *SectionHeader(int id) const { + assert(id >= 0 && id < SectionHeaderCount()); + return section_header_table_ + id; + } + + const uint8 *SectionBody(int id) const { + return OffsetToPointer(SectionHeader(id)->sh_offset); + } + + const Elf32_Word SectionBodySize(int id) const { + return SectionHeader(id)->sh_size; + } + + // Misc Segment Helpers + + const Elf32_Half ProgramSegmentHeaderCount() const { + return program_header_table_size_; + } + + const Elf32_Phdr *ProgramSegmentHeader(int id) const { + assert(id >= 0 && id < ProgramSegmentHeaderCount()); + return program_header_table_ + id; + } + + // The virtual memory address at which this program segment will be loaded + const Elf32_Addr ProgramSegmentMemoryBegin(int id) const { + return ProgramSegmentHeader(id)->p_vaddr; + } + + // The number of virtual memory bytes for this program segment + const Elf32_Word ProgramSegmentMemorySize(int id) const { + return ProgramSegmentHeader(id)->p_memsz; + } + + // Pointer into the source file for this program segment + const Elf32_Addr ProgramSegmentFileOffset(int id) const { + return ProgramSegmentHeader(id)->p_offset; + } + + // Number of file bytes for this program segment. Is <= ProgramMemorySize. + const Elf32_Word ProgramSegmentFileSize(int id) const { + return ProgramSegmentHeader(id)->p_filesz; + } + + // Misc address space helpers + + CheckBool IsValidRVA(RVA rva) const WARN_UNUSED_RESULT; + + // Convert an ELF relocation struction into an RVA + virtual CheckBool RelToRVA(Elf32_Rel rel, RVA* result) + const WARN_UNUSED_RESULT = 0; + + // Returns kNoOffset if there is no file offset corresponding to 'rva'. + CheckBool RVAToFileOffset(RVA rva, size_t* result) const WARN_UNUSED_RESULT; + + RVA FileOffsetToRVA(size_t offset) const WARN_UNUSED_RESULT; + + CheckBool RVAsToOffsets(std::vector<RVA>* rvas /*in*/, + std::vector<size_t>* offsets /*out*/); + + // Parsing Code used to really implement Disassemble + + CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT; + virtual CheckBool ParseRelocationSection( + const Elf32_Shdr *section_header, + AssemblyProgram* program) WARN_UNUSED_RESULT = 0; + CheckBool ParseProgbitsSection( + const Elf32_Shdr *section_header, + std::vector<size_t>::iterator* current_abs_offset, + std::vector<size_t>::iterator end_abs_offset, + std::vector<size_t>::iterator* current_rel_offset, + std::vector<size_t>::iterator end_rel_offset, + AssemblyProgram* program) WARN_UNUSED_RESULT; + CheckBool ParseSimpleRegion(size_t start_file_offset, + size_t end_file_offset, + AssemblyProgram* program) WARN_UNUSED_RESULT; + + CheckBool ParseAbs32Relocs() WARN_UNUSED_RESULT; + CheckBool ParseRel32RelocsFromSections() WARN_UNUSED_RESULT; + virtual CheckBool ParseRel32RelocsFromSection( + const Elf32_Shdr* section) WARN_UNUSED_RESULT = 0; + + Elf32_Ehdr *header_; + Elf32_Shdr *section_header_table_; + Elf32_Half section_header_table_size_; + + Elf32_Phdr *program_header_table_; + Elf32_Half program_header_table_size_; + + // Section header for default + const char *default_string_section_; + + std::vector<RVA> abs32_locations_; + std::vector<RVA> rel32_locations_; + + DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32); +}; + +} // namespace courgette + +#endif // COURGETTE_DISASSEMBLER_ELF_32_H_ diff --git a/courgette/disassembler_elf_32_arm.cc b/courgette/disassembler_elf_32_arm.cc new file mode 100644 index 0000000..b321e06 --- /dev/null +++ b/courgette/disassembler_elf_32_arm.cc @@ -0,0 +1,111 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "courgette/disassembler_elf_32_arm.h" + +#include <algorithm> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" + +#include "courgette/assembly_program.h" +#include "courgette/courgette.h" +#include "courgette/encoded_program.h" + +namespace courgette { + +DisassemblerElf32ARM::DisassemblerElf32ARM(const void* start, size_t length) + : DisassemblerElf32(start, length) { +} + +// Convert an ELF relocation struction into an RVA +CheckBool DisassemblerElf32ARM::RelToRVA(Elf32_Rel rel, RVA* result) const { + + // The rightmost byte of r_info is the type... + elf32_rel_arm_type_values type = + (elf32_rel_arm_type_values)(unsigned char)rel.r_info; + + // The other 3 bytes of r_info are the symbol + uint32 symbol = rel.r_info >> 8; + + switch(type) + { + case R_ARM_RELATIVE: + if (symbol != 0) + return false; + + // This is a basic ABS32 relocation address + *result = rel.r_offset; + return true; + + default: + return false; + } + + return false; +} + +CheckBool DisassemblerElf32ARM::ParseRelocationSection( + const Elf32_Shdr *section_header, + AssemblyProgram* program) { + // We can reproduce the R_386_RELATIVE entries in one of the relocation + // table based on other information in the patch, given these + // conditions.... + // + // All R_386_RELATIVE entries are: + // 1) In the same relocation table + // 2) Are consecutive + // 3) Are sorted in memory address order + // + // Happily, this is normally the case, but it's not required by spec + // so we check, and just don't do it if we don't match up. + + // The expectation is that one relocation section will contain + // all of our R_386_RELATIVE entries in the expected order followed + // by assorted other entries we can't use special handling for. + + bool match = true; + + // Walk all the bytes in the section, matching relocation table or not + size_t file_offset = section_header->sh_offset; + size_t section_end = section_header->sh_offset + section_header->sh_size; + + Elf32_Rel *section_relocs_iter = + (Elf32_Rel *)OffsetToPointer(section_header->sh_offset); + + uint32 section_relocs_count = section_header->sh_size / + section_header->sh_entsize; + + if (abs32_locations_.size() > section_relocs_count) + match = false; + + std::vector<RVA>::iterator reloc_iter = abs32_locations_.begin(); + + while (match && (reloc_iter != abs32_locations_.end())) { + if (section_relocs_iter->r_info != R_ARM_RELATIVE || + section_relocs_iter->r_offset != *reloc_iter) + match = false; + section_relocs_iter++; + reloc_iter++; + } + + if (match) { + // Skip over relocation tables + if (!program->EmitElfRelocationInstruction()) + return false; + file_offset += sizeof(Elf32_Rel) * abs32_locations_.size(); + } + + return ParseSimpleRegion(file_offset, section_end, program); +} + +CheckBool DisassemblerElf32ARM::ParseRel32RelocsFromSection( + const Elf32_Shdr* section_header) { + // TODO(paulgazz) find relative jumps in ARM assembly + return true; +} + +} // namespace courgette diff --git a/courgette/disassembler_elf_32_arm.h b/courgette/disassembler_elf_32_arm.h new file mode 100644 index 0000000..dcbc46e --- /dev/null +++ b/courgette/disassembler_elf_32_arm.h @@ -0,0 +1,42 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COURGETTE_DISASSEMBLER_ELF_32_ARM_H_ +#define COURGETTE_DISASSEMBLER_ELF_32_ARM_H_ + +#include "base/basictypes.h" +#include "courgette/disassembler_elf_32.h" +#include "courgette/memory_allocator.h" +#include "courgette/types_elf.h" + +namespace courgette { + +class AssemblyProgram; + +class DisassemblerElf32ARM : public DisassemblerElf32 { + public: + explicit DisassemblerElf32ARM(const void* start, size_t length); + + virtual ExecutableType kind() { return EXE_ELF_32_ARM; } + + virtual e_machine_values ElfEM() { return EM_ARM; } + + protected: + + virtual CheckBool RelToRVA(Elf32_Rel rel, RVA* result) + const WARN_UNUSED_RESULT; + + virtual CheckBool ParseRelocationSection( + const Elf32_Shdr *section_header, + AssemblyProgram* program) WARN_UNUSED_RESULT; + + virtual CheckBool ParseRel32RelocsFromSection( + const Elf32_Shdr* section) WARN_UNUSED_RESULT; + + DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32ARM); +}; + +} // namespace courgette + +#endif // COURGETTE_DISASSEMBLER_ELF_32_ARM_H_ diff --git a/courgette/disassembler_elf_32_x86.cc b/courgette/disassembler_elf_32_x86.cc index a857c96..00bb650 100644 --- a/courgette/disassembler_elf_32_x86.cc +++ b/courgette/disassembler_elf_32_x86.cc @@ -18,143 +18,7 @@ namespace courgette { DisassemblerElf32X86::DisassemblerElf32X86(const void* start, size_t length) - : Disassembler(start, length), - header_(NULL), - section_header_table_(NULL), - section_header_table_size_(0), - program_header_table_(NULL), - program_header_table_size_(0), - default_string_section_(NULL) { -} - -bool DisassemblerElf32X86::ParseHeader() { - if (length() < sizeof(Elf32_Ehdr)) - return Bad("Too small"); - - header_ = (Elf32_Ehdr *)start(); - - // Have magic for elf header? - if (header_->e_ident[0] != 0x7f || - header_->e_ident[1] != 'E' || - header_->e_ident[2] != 'L' || - header_->e_ident[3] != 'F') - return Bad("No Magic Number"); - - if (header_->e_type != ET_EXEC && - header_->e_type != ET_DYN) - return Bad("Not an executable file or shared library"); - - if (header_->e_machine != EM_386) - return Bad("Not a supported architecture"); - - if (header_->e_version != 1) - return Bad("Unknown file version"); - - if (header_->e_shentsize != sizeof(Elf32_Shdr)) - return Bad("Unexpected section header size"); - - if (header_->e_shoff >= length()) - return Bad("Out of bounds section header table offset"); - - section_header_table_ = (Elf32_Shdr *)OffsetToPointer(header_->e_shoff); - section_header_table_size_ = header_->e_shnum; - - if ((header_->e_shoff + header_->e_shnum ) >= length()) - return Bad("Out of bounds section header table"); - - if (header_->e_phoff >= length()) - return Bad("Out of bounds program header table offset"); - - program_header_table_ = (Elf32_Phdr *)OffsetToPointer(header_->e_phoff); - program_header_table_size_ = header_->e_phnum; - - if ((header_->e_phoff + header_->e_phnum) >= length()) - return Bad("Out of bounds program header table"); - - default_string_section_ = (const char *)SectionBody((int)header_->e_shstrndx); - - ReduceLength(DiscoverLength()); - - return Good(); -} - -bool DisassemblerElf32X86::Disassemble(AssemblyProgram* target) { - if (!ok()) - return false; - - // The Image Base is always 0 for ELF Executables - target->set_image_base(0); - - if (!ParseAbs32Relocs()) - return false; - - if (!ParseRel32RelocsFromSections()) - return false; - - if (!ParseFile(target)) - return false; - - target->DefaultAssignIndexes(); - - return true; -} - -uint32 DisassemblerElf32X86::DiscoverLength() { - uint32 result = 0; - - // Find the end of the last section - for (int section_id = 0; section_id < SectionHeaderCount(); section_id++) { - const Elf32_Shdr *section_header = SectionHeader(section_id); - - if (section_header->sh_type == SHT_NOBITS) - continue; - - uint32 section_end = section_header->sh_offset + section_header->sh_size; - - if (section_end > result) - result = section_end; - } - - // Find the end of the last segment - for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { - const Elf32_Phdr *segment_header = ProgramSegmentHeader(i); - - uint32 segment_end = segment_header->p_offset + segment_header->p_filesz; - - if (segment_end > result) - result = segment_end; - } - - uint32 section_table_end = header_->e_shoff + - (header_->e_shnum * sizeof(Elf32_Shdr)); - if (section_table_end > result) - result = section_table_end; - - uint32 segment_table_end = header_->e_phoff + - (header_->e_phnum * sizeof(Elf32_Phdr)); - if (segment_table_end > result) - result = segment_table_end; - - return result; -} - -CheckBool DisassemblerElf32X86::IsValidRVA(RVA rva) const { - - // It's valid if it's contained in any program segment - for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { - const Elf32_Phdr *segment_header = ProgramSegmentHeader(i); - - 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; + : DisassemblerElf32(start, length) { } // Convert an ELF relocation struction into an RVA @@ -196,151 +60,6 @@ CheckBool DisassemblerElf32X86::RelToRVA(Elf32_Rel rel, RVA* result) const { return false; } -// Returns RVA for an in memory address, or NULL. -CheckBool DisassemblerElf32X86::RVAToFileOffset(Elf32_Addr addr, - size_t* result) const { - - for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { - Elf32_Addr begin = ProgramSegmentMemoryBegin(i); - Elf32_Addr end = begin + ProgramSegmentMemorySize(i); - - if (addr >= begin && addr < end) { - Elf32_Addr offset = addr - begin; - - if (offset < ProgramSegmentFileSize(i)) { - *result = ProgramSegmentFileOffset(i) + offset; - return true; - } - } - } - - return false; -} - -RVA DisassemblerElf32X86::FileOffsetToRVA(size_t offset) const { - // File offsets can be 64 bit values, but we are dealing with 32 - // bit executables and so only need to support 32bit file sizes. - uint32 offset32 = (uint32)offset; - - for (int i = 0; i < SectionHeaderCount(); i++) { - - const Elf32_Shdr *section_header = SectionHeader(i); - - // These can appear to have a size in the file, but don't. - if (section_header->sh_type == SHT_NOBITS) - continue; - - Elf32_Off section_begin = section_header->sh_offset; - Elf32_Off section_end = section_begin + section_header->sh_size; - - if (offset32 >= section_begin && offset32 < section_end) { - return section_header->sh_addr + (offset32 - section_begin); - } - } - - return 0; -} - -CheckBool DisassemblerElf32X86::RVAsToOffsets(std::vector<RVA>* rvas, - std::vector<size_t>* offsets) { - offsets->clear(); - - for (std::vector<RVA>::iterator rva = rvas->begin(); - rva != rvas->end(); - rva++) { - - size_t offset; - - if (!RVAToFileOffset(*rva, &offset)) - return false; - - offsets->push_back(offset); - } - - return true; -} - -CheckBool DisassemblerElf32X86::ParseFile(AssemblyProgram* program) { - // Walk all the bytes in the file, whether or not in a section. - uint32 file_offset = 0; - - std::vector<size_t> abs_offsets; - std::vector<size_t> rel_offsets; - - if (!RVAsToOffsets(&abs32_locations_, &abs_offsets)) - return false; - - if (!RVAsToOffsets(&rel32_locations_, &rel_offsets)) - return false; - - std::vector<size_t>::iterator current_abs_offset = abs_offsets.begin(); - std::vector<size_t>::iterator current_rel_offset = rel_offsets.begin(); - - std::vector<size_t>::iterator end_abs_offset = abs_offsets.end(); - std::vector<size_t>::iterator end_rel_offset = rel_offsets.end(); - - for (int section_id = 0; - section_id < SectionHeaderCount(); - section_id++) { - - const Elf32_Shdr *section_header = SectionHeader(section_id); - - if (!ParseSimpleRegion(file_offset, - section_header->sh_offset, - program)) - return false; - file_offset = section_header->sh_offset; - - switch (section_header->sh_type) { - case SHT_REL: - if (!ParseRelocationSection(section_header, program)) - return false; - file_offset = section_header->sh_offset + section_header->sh_size; - break; - case SHT_PROGBITS: - if (!ParseProgbitsSection(section_header, - ¤t_abs_offset, end_abs_offset, - ¤t_rel_offset, end_rel_offset, - program)) - return false; - file_offset = section_header->sh_offset + section_header->sh_size; - break; - case SHT_NOBITS: - // Fall through - case SHT_INIT_ARRAY: - // Fall through - case SHT_FINI_ARRAY: - while (current_abs_offset != end_abs_offset && - *current_abs_offset >= section_header->sh_offset && - *current_abs_offset < - (section_header->sh_offset + section_header->sh_size)) { - // Skip any abs_offsets appear in the unsupported INIT_ARRAY section - VLOG(1) << "Skipping relocation entry for unsupported section: " << - section_header->sh_type; - current_abs_offset++; - } - break; - default: - if (current_abs_offset != end_abs_offset && - *current_abs_offset >= section_header->sh_offset && - *current_abs_offset < - (section_header->sh_offset + section_header->sh_size)) - VLOG(1) << "Relocation address in unrecognized ELF section: " << \ - section_header->sh_type; - break; - } - } - - // Rest of the file past the last section - if (!ParseSimpleRegion(file_offset, - length(), - program)) - return false; - - // Make certain we consume all of the relocations as expected - return (current_abs_offset == end_abs_offset); -} - CheckBool DisassemblerElf32X86::ParseRelocationSection( const Elf32_Shdr *section_header, AssemblyProgram* program) { @@ -395,163 +114,6 @@ CheckBool DisassemblerElf32X86::ParseRelocationSection( return ParseSimpleRegion(file_offset, section_end, program); } -CheckBool DisassemblerElf32X86::ParseProgbitsSection( - const Elf32_Shdr *section_header, - std::vector<size_t>::iterator* current_abs_offset, - std::vector<size_t>::iterator end_abs_offset, - std::vector<size_t>::iterator* current_rel_offset, - std::vector<size_t>::iterator end_rel_offset, - AssemblyProgram* program) { - - // Walk all the bytes in the file, whether or not in a section. - size_t file_offset = section_header->sh_offset; - size_t section_end = section_header->sh_offset + section_header->sh_size; - - Elf32_Addr origin = section_header->sh_addr; - size_t origin_offset = section_header->sh_offset; - if (!program->EmitOriginInstruction(origin)) - return false; - - while (file_offset < section_end) { - - if (*current_abs_offset != end_abs_offset && - file_offset > **current_abs_offset) - return false; - - while (*current_rel_offset != end_rel_offset && - file_offset > **current_rel_offset) { - (*current_rel_offset)++; - } - - size_t next_relocation = section_end; - - if (*current_abs_offset != end_abs_offset && - next_relocation > **current_abs_offset) - next_relocation = **current_abs_offset; - - // Rel offsets are heuristically derived, and might (incorrectly) overlap - // an Abs value, or the end of the section, so +3 to make sure there is - // room for the full 4 byte value. - if (*current_rel_offset != end_rel_offset && - next_relocation > (**current_rel_offset + 3)) - next_relocation = **current_rel_offset; - - if (next_relocation > file_offset) { - if (!ParseSimpleRegion(file_offset, next_relocation, program)) - return false; - - file_offset = next_relocation; - continue; - } - - if (*current_abs_offset != end_abs_offset && - file_offset == **current_abs_offset) { - - const uint8* p = OffsetToPointer(file_offset); - RVA target_rva = Read32LittleEndian(p); - - if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva))) - return false; - file_offset += sizeof(RVA); - (*current_abs_offset)++; - continue; - } - - if (*current_rel_offset != end_rel_offset && - file_offset == **current_rel_offset) { - - const uint8* p = OffsetToPointer(file_offset); - uint32 relative_target = Read32LittleEndian(p); - // 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) + - 4 + relative_target); - - if (!program->EmitRel32(program->FindOrMakeRel32Label(target_rva))) - return false; - file_offset += sizeof(RVA); - (*current_rel_offset)++; - continue; - } - } - - // Rest of the section (if any) - return ParseSimpleRegion(file_offset, section_end, program); -} - -CheckBool DisassemblerElf32X86::ParseSimpleRegion( - size_t start_file_offset, - size_t end_file_offset, - AssemblyProgram* program) { - - const uint8* start = OffsetToPointer(start_file_offset); - const uint8* end = OffsetToPointer(end_file_offset); - - const uint8* p = start; - - while (p < end) { - if (!program->EmitByteInstruction(*p)) - return false; - ++p; - } - - return true; -} - -CheckBool DisassemblerElf32X86::ParseAbs32Relocs() { - abs32_locations_.clear(); - - // Loop through sections for relocation sections - for (int section_id = 0; section_id < SectionHeaderCount(); section_id++) { - const Elf32_Shdr *section_header = SectionHeader(section_id); - - if (section_header->sh_type == SHT_REL) { - - Elf32_Rel *relocs_table = (Elf32_Rel *)SectionBody(section_id); - - int relocs_table_count = section_header->sh_size / - section_header->sh_entsize; - - // Elf32_Word relocation_section_id = section_header->sh_info; - - // Loop through relocation objects in the relocation section - for (int rel_id = 0; rel_id < relocs_table_count; rel_id++) { - RVA rva; - - // Quite a few of these conversions fail, and we simply skip - // them, that's okay. - if (RelToRVA(relocs_table[rel_id], &rva)) - abs32_locations_.push_back(rva); - } - } - } - - std::sort(abs32_locations_.begin(), abs32_locations_.end()); - return true; -} - -CheckBool DisassemblerElf32X86::ParseRel32RelocsFromSections() { - - rel32_locations_.clear(); - - // Loop through sections for relocation sections - for (int section_id = 0; - section_id < SectionHeaderCount(); - section_id++) { - - const Elf32_Shdr *section_header = SectionHeader(section_id); - - if (section_header->sh_type != SHT_PROGBITS) - continue; - - if (!ParseRel32RelocsFromSection(section_header)) - return false; - } - - std::sort(rel32_locations_.begin(), rel32_locations_.end()); - return true; -} - CheckBool DisassemblerElf32X86::ParseRel32RelocsFromSection( const Elf32_Shdr* section_header) { diff --git a/courgette/disassembler_elf_32_x86.h b/courgette/disassembler_elf_32_x86.h index c797a8b..6096781 100644 --- a/courgette/disassembler_elf_32_x86.h +++ b/courgette/disassembler_elf_32_x86.h @@ -6,7 +6,7 @@ #define COURGETTE_DISASSEMBLER_ELF_32_X86_H_ #include "base/basictypes.h" -#include "courgette/disassembler.h" +#include "courgette/disassembler_elf_32.h" #include "courgette/memory_allocator.h" #include "courgette/types_elf.h" @@ -14,127 +14,26 @@ namespace courgette { class AssemblyProgram; -class DisassemblerElf32X86 : public Disassembler { +class DisassemblerElf32X86 : public DisassemblerElf32 { public: explicit DisassemblerElf32X86(const void* start, size_t length); virtual ExecutableType kind() { return EXE_ELF_32_X86; } - // Returns 'true' if the buffer appears to point to a valid ELF executable - // for X86 32 bitWindows 32 bit. If ParseHeader() succeeds, other member - // functions may be called. - virtual bool ParseHeader(); - - virtual bool Disassemble(AssemblyProgram* target); - - // Public for unittests only - std::vector<RVA> &Abs32Locations() { return abs32_locations_; } - std::vector<RVA> &Rel32Locations() { return rel32_locations_; } + virtual e_machine_values ElfEM() { return EM_386; } protected: - uint32 DiscoverLength(); - - // Misc Section Helpers - - const Elf32_Half SectionHeaderCount() const { - return section_header_table_size_; - } - - const Elf32_Shdr *SectionHeader(int id) const { - assert(id >= 0 && id < SectionHeaderCount()); - return section_header_table_ + id; - } - - const uint8 *SectionBody(int id) const { - return OffsetToPointer(SectionHeader(id)->sh_offset); - } - - const Elf32_Word SectionBodySize(int id) const { - return SectionHeader(id)->sh_size; - } - - // Misc Segment Helpers - - const Elf32_Half ProgramSegmentHeaderCount() const { - return program_header_table_size_; - } - - const Elf32_Phdr *ProgramSegmentHeader(int id) const { - assert(id >= 0 && id < ProgramSegmentHeaderCount()); - return program_header_table_ + id; - } - - // The virtual memory address at which this program segment will be loaded - const Elf32_Addr ProgramSegmentMemoryBegin(int id) const { - return ProgramSegmentHeader(id)->p_vaddr; - } - - // The number of virtual memory bytes for this program segment - const Elf32_Word ProgramSegmentMemorySize(int id) const { - return ProgramSegmentHeader(id)->p_memsz; - } - - // Pointer into the source file for this program segment - const Elf32_Addr ProgramSegmentFileOffset(int id) const { - return ProgramSegmentHeader(id)->p_offset; - } + virtual CheckBool RelToRVA(Elf32_Rel rel, RVA* result) + const WARN_UNUSED_RESULT; - // Number of file bytes for this program segment. Is <= ProgramMemorySize. - const Elf32_Word ProgramSegmentFileSize(int id) const { - return ProgramSegmentHeader(id)->p_filesz; - } - - // Misc address space helpers - - CheckBool IsValidRVA(RVA rva) const WARN_UNUSED_RESULT; - - // Convert an ELF relocation struction into an RVA - CheckBool RelToRVA(Elf32_Rel rel, RVA* result) const WARN_UNUSED_RESULT; - - // Returns kNoOffset if there is no file offset corresponding to 'rva'. - CheckBool RVAToFileOffset(RVA rva, size_t* result) const WARN_UNUSED_RESULT; - - RVA FileOffsetToRVA(size_t offset) const WARN_UNUSED_RESULT; - - CheckBool RVAsToOffsets(std::vector<RVA>* rvas /*in*/, - std::vector<size_t>* offsets /*out*/); - - // Parsing Code used to really implement Disassemble - - CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT; - CheckBool ParseRelocationSection( + virtual CheckBool ParseRelocationSection( const Elf32_Shdr *section_header, AssemblyProgram* program) WARN_UNUSED_RESULT; - CheckBool ParseProgbitsSection( - const Elf32_Shdr *section_header, - std::vector<size_t>::iterator* current_abs_offset, - std::vector<size_t>::iterator end_abs_offset, - std::vector<size_t>::iterator* current_rel_offset, - std::vector<size_t>::iterator end_rel_offset, - AssemblyProgram* program) WARN_UNUSED_RESULT; - CheckBool ParseSimpleRegion(size_t start_file_offset, - size_t end_file_offset, - AssemblyProgram* program) WARN_UNUSED_RESULT; - CheckBool ParseAbs32Relocs() WARN_UNUSED_RESULT; - CheckBool ParseRel32RelocsFromSections() WARN_UNUSED_RESULT; - CheckBool ParseRel32RelocsFromSection( + virtual CheckBool ParseRel32RelocsFromSection( const Elf32_Shdr* section) WARN_UNUSED_RESULT; - Elf32_Ehdr *header_; - Elf32_Shdr *section_header_table_; - Elf32_Half section_header_table_size_; - - Elf32_Phdr *program_header_table_; - Elf32_Half program_header_table_size_; - - // Section header for default - const char *default_string_section_; - - std::vector<RVA> abs32_locations_; - std::vector<RVA> rel32_locations_; - DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32X86); }; diff --git a/courgette/ensemble_apply.cc b/courgette/ensemble_apply.cc index 61a3602..7c7cca8 100644 --- a/courgette/ensemble_apply.cc +++ b/courgette/ensemble_apply.cc @@ -145,6 +145,9 @@ Status EnsemblePatchApplication::ReadInitialParameters( case EXE_ELF_32_X86: patcher = new PatcherX86_32(base_region_); break; + case EXE_ELF_32_ARM: + patcher = new PatcherX86_32(base_region_); + break; } if (patcher) diff --git a/courgette/ensemble_create.cc b/courgette/ensemble_create.cc index c098710..84029be 100644 --- a/courgette/ensemble_create.cc +++ b/courgette/ensemble_create.cc @@ -85,6 +85,15 @@ TransformationPatchGenerator* MakeGenerator(Element* old_element, EXE_ELF_32_X86); return generator; } + case EXE_ELF_32_ARM: { + TransformationPatchGenerator* generator = + new PatchGeneratorX86_32( + old_element, + new_element, + new PatcherX86_32(old_element->region()), + EXE_ELF_32_ARM); + return generator; + } } LOG(WARNING) << "Unexpected Element::Kind " << old_element->kind(); diff --git a/courgette/types_elf.h b/courgette/types_elf.h index 9708486..f7fce71 100644 --- a/courgette/types_elf.h +++ b/courgette/types_elf.h @@ -50,6 +50,7 @@ enum e_type_values { enum e_machine_values { EM_NONE = 0, // No machine EM_386 = 3, // Intel Architecture + EM_ARM = 40, // ARM Architecture EM_x86_64 = 62, // Intel x86-64 Architecture // Other values skipped }; @@ -140,4 +141,8 @@ enum elf32_rel_386_type_values { R_386_TLS_TPOFF = 14, }; +enum elf32_rel_arm_type_values { + R_ARM_RELATIVE = 23, +}; + #endif // COURGETTE_ELF_TYPES_H_ |