summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--courgette/assembly_program.cc17
-rw-r--r--courgette/assembly_program.h5
-rw-r--r--courgette/disassembler_elf_32.cc29
-rw-r--r--courgette/disassembler_elf_32.h1
-rw-r--r--courgette/disassembler_elf_32_arm.cc61
-rw-r--r--courgette/encoded_program.cc37
-rw-r--r--courgette/encoded_program.h8
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);