diff options
author | paulgazz@chromium.org <paulgazz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-18 22:07:53 +0000 |
---|---|---|
committer | paulgazz@chromium.org <paulgazz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-18 22:07:53 +0000 |
commit | a8e80416be9ccd606ce54f7f192b91133bb23b98 (patch) | |
tree | 0972d2fe6b393a5e07e7a1267be5b616643b7eec /courgette | |
parent | ba79a799579a5417511d472071e3f8fc5e2b67a5 (diff) | |
download | chromium_src-a8e80416be9ccd606ce54f7f192b91133bb23b98.zip chromium_src-a8e80416be9ccd606ce54f7f192b91133bb23b98.tar.gz chromium_src-a8e80416be9ccd606ce54f7f192b91133bb23b98.tar.bz2 |
Fixed Courgette to correctly regenerate the ELF relocation table for
ARM binaries.
Note for reviewers:
Don: general courgette correctness
Ben: style, correctness
BUG=258648
Review URL: https://chromiumcodereview.appspot.com/19022007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212449 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'courgette')
-rw-r--r-- | courgette/assembly_program.cc | 17 | ||||
-rw-r--r-- | courgette/assembly_program.h | 5 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.cc | 29 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.h | 1 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_arm.cc | 61 | ||||
-rw-r--r-- | courgette/encoded_program.cc | 37 | ||||
-rw-r--r-- | courgette/encoded_program.h | 8 |
7 files changed, 122 insertions, 36 deletions
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc index 9225578..6f137210 100644 --- a/courgette/assembly_program.cc +++ b/courgette/assembly_program.cc @@ -27,6 +27,8 @@ enum OP { DEFBYTE, // DEFBYTE <value> - emit a byte literal. REL32, // REL32 <label> - emit a rel32 encoded reference to 'label'. ABS32, // REL32 <label> - emit am abs32 encoded reference to 'label'. + REL32ARM, // REL32ARM <c_op> <label> - arm-specific rel32 reference + MAKEELFARMRELOCS, // Generates a base relocation table. LAST_OP }; @@ -71,6 +73,12 @@ class ElfRelocsInstruction : public Instruction { ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {} }; +// Emits an ELF ARM relocation table. +class ElfARMRelocsInstruction : public Instruction { + public: + ElfARMRelocsInstruction() : Instruction(MAKEELFARMRELOCS) {} +}; + // Emits a single byte. class ByteInstruction : public Instruction { public: @@ -123,6 +131,10 @@ CheckBool AssemblyProgram::EmitElfRelocationInstruction() { return Emit(new(std::nothrow) ElfRelocsInstruction()); } +CheckBool AssemblyProgram::EmitElfARMRelocationInstruction() { + return Emit(new(std::nothrow) ElfARMRelocsInstruction()); +} + CheckBool AssemblyProgram::EmitOriginInstruction(RVA rva) { return Emit(new(std::nothrow) OriginInstruction(rva)); } @@ -378,6 +390,11 @@ EncodedProgram* AssemblyProgram::Encode() const { return NULL; break; } + case MAKEELFARMRELOCS: { + if (!encoded->AddElfARMMakeRelocs()) + return NULL; + break; + } default: { NOTREACHED() << "Unknown Insn OP kind"; } diff --git a/courgette/assembly_program.h b/courgette/assembly_program.h index 2a68e51..bb2d34c 100644 --- a/courgette/assembly_program.h +++ b/courgette/assembly_program.h @@ -71,9 +71,12 @@ class AssemblyProgram { // Generates an entire base relocation table. CheckBool EmitPeRelocsInstruction() WARN_UNUSED_RESULT; - // Generates an ELF style relocation table. + // Generates an ELF style relocation table for X86. CheckBool EmitElfRelocationInstruction() WARN_UNUSED_RESULT; + // Generates an ELF style relocation table for ARM. + CheckBool EmitElfARMRelocationInstruction() WARN_UNUSED_RESULT; + // Following instruction will be assembled at address 'rva'. CheckBool EmitOriginInstruction(RVA rva) WARN_UNUSED_RESULT; diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc index bd49ff1..91ccd45 100644 --- a/courgette/disassembler_elf_32.cc +++ b/courgette/disassembler_elf_32.cc @@ -427,7 +427,7 @@ CheckBool DisassemblerElf32::ParseAbs32Relocs() { // Quite a few of these conversions fail, and we simply skip // them, that's okay. - if (RelToRVA(relocs_table[rel_id], &rva)) + if (RelToRVA(relocs_table[rel_id], &rva) && CheckSection(rva)) abs32_locations_.push_back(rva); } } @@ -437,6 +437,33 @@ CheckBool DisassemblerElf32::ParseAbs32Relocs() { return true; } +CheckBool DisassemblerElf32::CheckSection(RVA rva) { + size_t offset; + + if (!RVAToFileOffset(rva, &offset)) { + return false; + } + + for (int section_id = 0; + section_id < SectionHeaderCount(); + section_id++) { + + const Elf32_Shdr *section_header = SectionHeader(section_id); + + if (offset >= section_header->sh_offset && + offset < (section_header->sh_offset + section_header->sh_size)) { + switch (section_header->sh_type) { + case SHT_REL: + // Fall-through + case SHT_PROGBITS: + return true; + } + } + } + + return false; +} + CheckBool DisassemblerElf32::ParseRel32RelocsFromSections() { rel32_locations_.clear(); diff --git a/courgette/disassembler_elf_32.h b/courgette/disassembler_elf_32.h index b1832dc..3f63c43 100644 --- a/courgette/disassembler_elf_32.h +++ b/courgette/disassembler_elf_32.h @@ -129,6 +129,7 @@ class DisassemblerElf32 : public Disassembler { AssemblyProgram* program) WARN_UNUSED_RESULT; CheckBool ParseAbs32Relocs() WARN_UNUSED_RESULT; + CheckBool CheckSection(RVA rva) WARN_UNUSED_RESULT; CheckBool ParseRel32RelocsFromSections() WARN_UNUSED_RESULT; virtual CheckBool ParseRel32RelocsFromSection( const Elf32_Shdr* section) WARN_UNUSED_RESULT = 0; diff --git a/courgette/disassembler_elf_32_arm.cc b/courgette/disassembler_elf_32_arm.cc index b321e06..f271020 100644 --- a/courgette/disassembler_elf_32_arm.cc +++ b/courgette/disassembler_elf_32_arm.cc @@ -51,20 +51,20 @@ CheckBool DisassemblerElf32ARM::RelToRVA(Elf32_Rel rel, RVA* result) const { 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 + // This method compresses a contiguous stretch of R_ARM_RELATIVE + // entries in the relocation table with a Courgette relocation table + // instruction. It skips any entries at the beginning that appear + // in a section that Courgette doesn't support, e.g. INIT. + // Specifically, the entries should be + // (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 + // all of our R_ARM_RELATIVE entries in the expected order followed // by assorted other entries we can't use special handling for. bool match = true; @@ -82,21 +82,36 @@ CheckBool DisassemblerElf32ARM::ParseRelocationSection( if (abs32_locations_.size() > section_relocs_count) match = false; - std::vector<RVA>::iterator reloc_iter = abs32_locations_.begin(); + if (!abs32_locations_.empty()) { + 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++; - } + for (uint32 i = 0; i < section_relocs_count; i++) { + if (section_relocs_iter->r_offset == *reloc_iter) + break; - if (match) { - // Skip over relocation tables - if (!program->EmitElfRelocationInstruction()) - return false; - file_offset += sizeof(Elf32_Rel) * abs32_locations_.size(); + if (!ParseSimpleRegion(file_offset, file_offset + sizeof(Elf32_Rel), + program)) + return false; + + file_offset += sizeof(Elf32_Rel); + ++section_relocs_iter; + } + + 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++; + file_offset += sizeof(Elf32_Rel); + } + + if (match) { + // Skip over relocation tables + if (!program->EmitElfARMRelocationInstruction()) + return false; + } } return ParseSimpleRegion(file_offset, section_end, program); diff --git a/courgette/encoded_program.cc b/courgette/encoded_program.cc index 26cbf4b..b7c9b55 100644 --- a/courgette/encoded_program.cc +++ b/courgette/encoded_program.cc @@ -15,6 +15,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "courgette/courgette.h" +#include "courgette/disassembler_elf_32_arm.h" #include "courgette/streams.h" #include "courgette/types_elf.h" @@ -250,6 +251,10 @@ CheckBool EncodedProgram::AddElfMakeRelocs() { return ops_.push_back(MAKE_ELF_RELOCATION_TABLE); } +CheckBool EncodedProgram::AddElfARMMakeRelocs() { + return ops_.push_back(MAKE_ELF_ARM_RELOCATION_TABLE); +} + void EncodedProgram::DebuggingSummary() { VLOG(1) << "EncodedProgram Summary" << "\n image base " << image_base_ @@ -405,7 +410,7 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) { RVA current_rva = 0; bool pending_pe_relocation_table = false; - bool pending_elf_relocation_table = false; + Elf32_Word pending_elf_relocation_table_type = 0; SinkStream bytes_following_relocation_table; SinkStream* output = final_buffer; @@ -505,15 +510,28 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) { // emitting an ORIGIN after the MAKE_BASE_RELOCATION_TABLE. } + case MAKE_ELF_ARM_RELOCATION_TABLE: { + // We can see the base relocation anywhere, but we only have the + // information to generate it at the very end. So we divert the bytes + // we are generating to a temporary stream. + if (pending_elf_relocation_table_type) // Can't have two relocation + // tables. + return false; + + pending_elf_relocation_table_type = R_ARM_RELATIVE; + output = &bytes_following_relocation_table; + break; + } + case MAKE_ELF_RELOCATION_TABLE: { // We can see the base relocation anywhere, but we only have the // information to generate it at the very end. So we divert the bytes // we are generating to a temporary stream. - if (pending_elf_relocation_table) // Can't have two relocation - // tables. + if (pending_elf_relocation_table_type) // Can't have two relocation + // tables. return false; - pending_elf_relocation_table = true; + pending_elf_relocation_table_type = R_386_RELATIVE; output = &bytes_following_relocation_table; break; } @@ -526,8 +544,9 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) { return false; } - if (pending_elf_relocation_table) { - if (!GenerateElfRelocations(final_buffer) || + if (pending_elf_relocation_table_type) { + if (!GenerateElfRelocations(pending_elf_relocation_table_type, + final_buffer) || !final_buffer->Append(&bytes_following_relocation_table)) return false; } @@ -602,13 +621,13 @@ CheckBool EncodedProgram::GeneratePeRelocations(SinkStream* buffer) { return ok; } -CheckBool EncodedProgram::GenerateElfRelocations(SinkStream* buffer) { +CheckBool EncodedProgram::GenerateElfRelocations(Elf32_Word r_info, + SinkStream* buffer) { std::sort(abs32_relocs_.begin(), abs32_relocs_.end()); Elf32_Rel relocation_block; - // We only handle this specific type of relocation, so far. - relocation_block.r_info = R_386_RELATIVE; + relocation_block.r_info = r_info; bool ok = true; for (size_t i = 0; ok && i < abs32_relocs_.size(); ++i) { diff --git a/courgette/encoded_program.h b/courgette/encoded_program.h index 62f1439..0de4f6b 100644 --- a/courgette/encoded_program.h +++ b/courgette/encoded_program.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "courgette/disassembler.h" #include "courgette/memory_allocator.h" +#include "courgette/types_elf.h" namespace courgette { @@ -45,6 +46,7 @@ class EncodedProgram { CheckBool AddAbs32(int label_index) WARN_UNUSED_RESULT; CheckBool AddPeMakeRelocs() WARN_UNUSED_RESULT; CheckBool AddElfMakeRelocs() WARN_UNUSED_RESULT; + CheckBool AddElfARMMakeRelocs() WARN_UNUSED_RESULT; // (3) Serialize binary assembly language tables to a set of streams. CheckBool WriteTo(SinkStreamSet* streams) WARN_UNUSED_RESULT; @@ -70,7 +72,8 @@ class EncodedProgram { ABS32 = 4, // ABS32 <index> - emit abs32 encoded reference to address at // address table offset <index> MAKE_PE_RELOCATION_TABLE = 5, // Emit PE base relocation table blocks. - MAKE_ELF_RELOCATION_TABLE = 6, // Emit Elf relocation table. + MAKE_ELF_RELOCATION_TABLE = 6, // Emit Elf relocation table for X86 + MAKE_ELF_ARM_RELOCATION_TABLE = 7, // Emit Elf relocation table for ARM }; typedef NoThrowBuffer<RVA> RvaVector; @@ -80,7 +83,8 @@ class EncodedProgram { void DebuggingSummary(); CheckBool GeneratePeRelocations(SinkStream *buffer) WARN_UNUSED_RESULT; - CheckBool GenerateElfRelocations(SinkStream *buffer) WARN_UNUSED_RESULT; + CheckBool GenerateElfRelocations(Elf32_Word pending_elf_relocation_table, + SinkStream *buffer) WARN_UNUSED_RESULT; CheckBool DefineLabelCommon(RvaVector*, int, RVA) WARN_UNUSED_RESULT; void FinishLabelsCommon(RvaVector* addresses); |