Skip to content

Commit

Permalink
Fixed Courgette to correctly regenerate the ELF relocation table for
Browse files Browse the repository at this point in the history
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
  • Loading branch information
paulgazz@chromium.org committed Jul 18, 2013
1 parent ba79a79 commit a8e8041
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 36 deletions.
17 changes: 17 additions & 0 deletions courgette/assembly_program.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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";
}
Expand Down
5 changes: 4 additions & 1 deletion courgette/assembly_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
29 changes: 28 additions & 1 deletion courgette/disassembler_elf_32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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();
Expand Down
1 change: 1 addition & 0 deletions courgette/disassembler_elf_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
61 changes: 38 additions & 23 deletions courgette/disassembler_elf_32_arm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
37 changes: 28 additions & 9 deletions courgette/encoded_program.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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_
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions courgette/encoded_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "courgette/disassembler.h"
#include "courgette/memory_allocator.h"
#include "courgette/types_elf.h"

namespace courgette {

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);

Expand Down

0 comments on commit a8e8041

Please sign in to comment.