summaryrefslogtreecommitdiffstats
path: root/courgette
diff options
context:
space:
mode:
Diffstat (limited to 'courgette')
-rw-r--r--courgette/assembly_program.cc32
-rw-r--r--courgette/assembly_program.h5
-rw-r--r--courgette/bsdiff_memory_unittest.cc6
-rw-r--r--courgette/courgette.gyp5
-rw-r--r--courgette/courgette.h1
-rw-r--r--courgette/disassembler.cc9
-rw-r--r--courgette/disassembler.h2
-rw-r--r--courgette/disassembler_elf_32_x86.cc602
-rw-r--r--courgette/disassembler_elf_32_x86.h143
-rw-r--r--courgette/disassembler_elf_32_x86_unittest.cc71
-rw-r--r--courgette/disassembler_win32_x86.cc2
-rw-r--r--courgette/encode_decode_unittest.cc29
-rw-r--r--courgette/encoded_program.cc67
-rw-r--r--courgette/encoded_program.h26
-rw-r--r--courgette/encoded_program_fuzz_unittest.cc3
-rw-r--r--courgette/ensemble_apply.cc3
-rw-r--r--courgette/ensemble_create.cc9
-rw-r--r--courgette/patch_generator_x86_32.h6
-rw-r--r--courgette/types_elf.h141
19 files changed, 1111 insertions, 51 deletions
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc
index f759e16..9225578 100644
--- a/courgette/assembly_program.cc
+++ b/courgette/assembly_program.cc
@@ -22,7 +22,8 @@ namespace courgette {
// Opcodes of simple assembly language
enum OP {
ORIGIN, // ORIGIN <rva> - set current address for assembly.
- MAKERELOCS, // Generates a base relocation table.
+ MAKEPERELOCS, // Generates a base relocation table.
+ MAKEELFRELOCS, // Generates a base relocation table.
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'.
@@ -58,10 +59,16 @@ class OriginInstruction : public Instruction {
RVA rva_;
};
-// Emits an entire base relocation table.
-class MakeRelocsInstruction : public Instruction {
+// Emits an entire PE base relocation table.
+class PeRelocsInstruction : public Instruction {
public:
- MakeRelocsInstruction() : Instruction(MAKERELOCS) {}
+ PeRelocsInstruction() : Instruction(MAKEPERELOCS) {}
+};
+
+// Emits an ELF relocation table.
+class ElfRelocsInstruction : public Instruction {
+ public:
+ ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {}
};
// Emits a single byte.
@@ -108,8 +115,12 @@ AssemblyProgram::~AssemblyProgram() {
DeleteContainedLabels(abs32_labels_);
}
-CheckBool AssemblyProgram::EmitMakeRelocsInstruction() {
- return Emit(new(std::nothrow) MakeRelocsInstruction());
+CheckBool AssemblyProgram::EmitPeRelocsInstruction() {
+ return Emit(new(std::nothrow) PeRelocsInstruction());
+}
+
+CheckBool AssemblyProgram::EmitElfRelocationInstruction() {
+ return Emit(new(std::nothrow) ElfRelocsInstruction());
}
CheckBool AssemblyProgram::EmitOriginInstruction(RVA rva) {
@@ -357,8 +368,13 @@ EncodedProgram* AssemblyProgram::Encode() const {
return NULL;
break;
}
- case MAKERELOCS: {
- if (!encoded->AddMakeRelocs())
+ case MAKEPERELOCS: {
+ if (!encoded->AddPeMakeRelocs())
+ return NULL;
+ break;
+ }
+ case MAKEELFRELOCS: {
+ if (!encoded->AddElfMakeRelocs())
return NULL;
break;
}
diff --git a/courgette/assembly_program.h b/courgette/assembly_program.h
index 5c6b1b1..3d231c2 100644
--- a/courgette/assembly_program.h
+++ b/courgette/assembly_program.h
@@ -69,7 +69,10 @@ class AssemblyProgram {
// Instructions will be assembled in the order they are emitted.
// Generates an entire base relocation table.
- CheckBool EmitMakeRelocsInstruction() WARN_UNUSED_RESULT;
+ CheckBool EmitPeRelocsInstruction() WARN_UNUSED_RESULT;
+
+ // Generates an ELF style relocation table.
+ CheckBool EmitElfRelocationInstruction() WARN_UNUSED_RESULT;
// Following instruction will be assembled at address 'rva'.
CheckBool EmitOriginInstruction(RVA rva) WARN_UNUSED_RESULT;
diff --git a/courgette/bsdiff_memory_unittest.cc b/courgette/bsdiff_memory_unittest.cc
index ce80eb7..f1718e2 100644
--- a/courgette/bsdiff_memory_unittest.cc
+++ b/courgette/bsdiff_memory_unittest.cc
@@ -117,3 +117,9 @@ TEST_F(BSDiffMemoryTest, TestDifferentExes) {
std::string file2 = FileContents("setup2.exe");
GenerateAndTestPatch(file1, file2);
}
+
+TEST_F(BSDiffMemoryTest, TestDifferentElfs) {
+ std::string file1 = FileContents("elf-32-1");
+ std::string file2 = FileContents("elf-32-2");
+ GenerateAndTestPatch(file1, file2);
+}
diff --git a/courgette/courgette.gyp b/courgette/courgette.gyp
index 6233d77..31276ae 100644
--- a/courgette/courgette.gyp
+++ b/courgette/courgette.gyp
@@ -22,6 +22,8 @@
'difference_estimator.h',
'disassembler.cc',
'disassembler.h',
+ 'disassembler_elf_32_x86.cc',
+ 'disassembler_elf_32_x86.h',
'disassembler_win32_x86.cc',
'disassembler_win32_x86.h',
'encoded_program.cc',
@@ -37,6 +39,8 @@
'simple_delta.h',
'streams.cc',
'streams.h',
+ 'types_elf.h',
+ 'types_win_pe.h',
'patch_generator_x86_32.h',
'patcher_x86_32.h',
],
@@ -89,6 +93,7 @@
'base_test_unittest.cc',
'base_test_unittest.h',
'difference_estimator_unittest.cc',
+ 'disassembler_elf_32_x86_unittest.cc',
'disassembler_win32_x86_unittest.cc',
'encoded_program_unittest.cc',
'encode_decode_unittest.cc',
diff --git a/courgette/courgette.h b/courgette/courgette.h
index 20a25ea..a58f16d 100644
--- a/courgette/courgette.h
+++ b/courgette/courgette.h
@@ -55,6 +55,7 @@ enum Status {
enum ExecutableType {
EXE_UNKNOWN = 0,
EXE_WIN_32_X86 = 1,
+ EXE_ELF_32_X86 = 2,
};
class SinkStream;
diff --git a/courgette/disassembler.cc b/courgette/disassembler.cc
index 5514be9..103bbe0 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_x86.h"
#include "courgette/disassembler_win32_x86.h"
#include "courgette/encoded_program.h"
@@ -30,8 +31,14 @@ Disassembler* DetectDisassembler(const void* buffer, size_t length) {
disassembler = new DisassemblerWin32X86(buffer, length);
if (disassembler->ParseHeader())
return disassembler;
+ else
+ delete disassembler;
- delete disassembler;
+ disassembler = new DisassemblerElf32X86(buffer, length);
+ if (disassembler->ParseHeader())
+ return disassembler;
+ else
+ delete disassembler;
return NULL;
}
diff --git a/courgette/disassembler.h b/courgette/disassembler.h
index 85c0c3d..2de67fd 100644
--- a/courgette/disassembler.h
+++ b/courgette/disassembler.h
@@ -68,7 +68,7 @@ class Disassembler {
}
// Reduce the length of the image in memory. Does not actually free
- // (or realloc) any memory. Unusally only called via ParseHeader()
+ // (or realloc) any memory. Usually only called via ParseHeader()
void ReduceLength(size_t reduced_length);
private:
diff --git a/courgette/disassembler_elf_32_x86.cc b/courgette/disassembler_elf_32_x86.cc
new file mode 100644
index 0000000..5f3ba95
--- /dev/null
+++ b/courgette/disassembler_elf_32_x86.cc
@@ -0,0 +1,602 @@
+// Copyright (c) 2011 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_x86.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 {
+
+DisassemblerElf32X86::DisassemblerElf32X86(const void* start, size_t length)
+ : Disassembler(start, length) {
+}
+
+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;
+}
+
+// Convert an ELF relocation struction into an RVA
+CheckBool DisassemblerElf32X86::RelToRVA(Elf32_Rel rel, RVA* result) const {
+
+ // The rightmost byte of r_info is the type...
+ elf32_rel_386_type_values type =
+ (elf32_rel_386_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_386_NONE:
+ case R_386_32:
+ case R_386_PC32:
+ case R_386_GOT32:
+ case R_386_PLT32:
+ case R_386_COPY:
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ return false;
+
+ case R_386_RELATIVE:
+ if (symbol != 0)
+ return false;
+
+ // This is a basic ABS32 relocation address
+ *result = rel.r_offset;
+ return true;
+
+ case R_386_GOTOFF:
+ case R_386_GOTPC:
+ case R_386_TLS_TPOFF:
+ return false;
+ }
+
+ 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) {
+ bool ok = true;
+
+ // 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 (ok)
+ ok = RVAsToOffsets(&abs32_locations_, &abs_offsets);
+
+ if (ok)
+ ok = RVAsToOffsets(&rel32_locations_, &rel_offsets);
+
+ 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;
+ ok && (section_id < SectionHeaderCount());
+ section_id++) {
+
+ const Elf32_Shdr *section_header = SectionHeader(section_id);
+
+ if (ok) {
+ ok = ParseSimpleRegion(file_offset,
+ section_header->sh_offset,
+ program);
+ file_offset = section_header->sh_offset;
+ }
+
+ switch (section_header->sh_type) {
+ case SHT_REL:
+ if (ok) {
+ ok = ParseRelocationSection(section_header, program);
+ file_offset = section_header->sh_offset + section_header->sh_size;
+ }
+ break;
+ case SHT_PROGBITS:
+ if (ok) {
+ ok = ParseProgbitsSection(section_header,
+ &current_abs_offset, end_abs_offset,
+ &current_rel_offset, end_rel_offset,
+ program);
+ file_offset = section_header->sh_offset + section_header->sh_size;
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Rest of the file past the last section
+ if (ok) {
+ ok = ParseSimpleRegion(file_offset,
+ length(),
+ program);
+ }
+
+ // Make certain we consume all of the relocations as expected
+ ok = ok && (current_abs_offset == end_abs_offset);
+
+ return ok;
+}
+
+CheckBool DisassemblerElf32X86::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 ok = true;
+ 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_386_RELATIVE ||
+ section_relocs_iter->r_offset != *reloc_iter)
+ match = false;
+ section_relocs_iter++;
+ reloc_iter++;
+ }
+
+ if (match) {
+ // Skip over relocation tables
+ ok = program->EmitElfRelocationInstruction();
+ file_offset += sizeof(Elf32_Rel) * abs32_locations_.size();
+ }
+
+ if (ok) {
+ ok = ParseSimpleRegion(file_offset, section_end, program);
+ }
+
+ return ok;
+}
+
+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) {
+
+ bool ok = true;
+
+ // 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;
+ ok = program->EmitOriginInstruction(origin);
+
+ while (ok && file_offset < section_end) {
+
+ if (*current_abs_offset != end_abs_offset &&
+ file_offset > **current_abs_offset) {
+ ok = 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 (ok && (next_relocation > file_offset)) {
+ ok = ParseSimpleRegion(file_offset, next_relocation, program);
+
+ file_offset = next_relocation;
+ continue;
+ }
+
+ if (ok &&
+ *current_abs_offset != end_abs_offset &&
+ file_offset == **current_abs_offset) {
+
+ const uint8* p = OffsetToPointer(file_offset);
+ RVA target_rva = Read32LittleEndian(p);
+
+ ok = program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva));
+ file_offset += sizeof(RVA);
+ (*current_abs_offset)++;
+ continue;
+ }
+
+ if (ok &&
+ *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);
+
+ ok = program->EmitRel32(program->FindOrMakeRel32Label(target_rva));
+ file_offset += sizeof(RVA);
+ (*current_rel_offset)++;
+ continue;
+ }
+ }
+
+ // Rest of the section (if any)
+ if (ok) {
+ ok = ParseSimpleRegion(file_offset, section_end, program);
+ }
+
+ return ok;
+}
+
+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;
+
+ bool ok = true;
+ while (p < end && ok) {
+ ok = program->EmitByteInstruction(*p);
+ ++p;
+ }
+
+ return ok;
+}
+
+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) {
+
+ uint32 start_file_offset = section_header->sh_offset;
+ uint32 end_file_offset = start_file_offset + section_header->sh_size;
+
+ const uint8* start_pointer = OffsetToPointer(start_file_offset);
+ const uint8* end_pointer = OffsetToPointer(end_file_offset);
+
+ // Quick way to convert from Pointer to RVA within a single Section is to
+ // subtract 'pointer_to_rva'.
+ const uint8* const adjust_pointer_to_rva = start_pointer -
+ section_header->sh_addr;
+
+ // Find the rel32 relocations.
+ const uint8* p = start_pointer;
+ while (p < end_pointer) {
+ //RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
+
+ // Heuristic discovery of rel32 locations in instruction stream: are the
+ // next few bytes the start of an instruction containing a rel32
+ // addressing mode?
+ const uint8* rel32 = NULL;
+
+ if (p + 5 < end_pointer) {
+ if (*p == 0xE8 || *p == 0xE9) { // jmp rel32 and call rel32
+ rel32 = p + 1;
+ }
+ }
+ if (p + 6 < end_pointer) {
+ if (*p == 0x0F && (*(p+1) & 0xF0) == 0x80) { // Jcc long form
+ if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely
+ rel32 = p + 2;
+ }
+ }
+ if (rel32) {
+ RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva);
+
+ RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32);
+ // To be valid, rel32 target must be within image, and within this
+ // section.
+ if (IsValidRVA(target_rva)) {
+ rel32_locations_.push_back(rel32_rva);
+#if COURGETTE_HISTOGRAM_TARGETS
+ ++rel32_target_rvas_[target_rva];
+#endif
+ p += 4;
+ continue;
+ }
+ }
+ p += 1;
+ }
+
+ return true;
+}
+
+} // namespace courgette
diff --git a/courgette/disassembler_elf_32_x86.h b/courgette/disassembler_elf_32_x86.h
new file mode 100644
index 0000000..c797a8b
--- /dev/null
+++ b/courgette/disassembler_elf_32_x86.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2011 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_X86_H_
+#define COURGETTE_DISASSEMBLER_ELF_32_X86_H_
+
+#include "base/basictypes.h"
+#include "courgette/disassembler.h"
+#include "courgette/memory_allocator.h"
+#include "courgette/types_elf.h"
+
+namespace courgette {
+
+class AssemblyProgram;
+
+class DisassemblerElf32X86 : public Disassembler {
+ 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_; }
+
+ 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
+ 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(
+ 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(
+ 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);
+};
+
+} // namespace courgette
+
+#endif // COURGETTE_DISASSEMBLER_ELF_32_X86_H_
diff --git a/courgette/disassembler_elf_32_x86_unittest.cc b/courgette/disassembler_elf_32_x86_unittest.cc
new file mode 100644
index 0000000..85c8e26
--- /dev/null
+++ b/courgette/disassembler_elf_32_x86_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 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/assembly_program.h"
+#include "courgette/base_test_unittest.h"
+#include "courgette/disassembler_elf_32_x86.h"
+
+class DisassemblerElf32X86Test : public BaseTest {
+ public:
+
+ void TestExe(const char* file_name,
+ size_t expected_abs_count,
+ size_t expected_rel_count) const;
+};
+
+void DisassemblerElf32X86Test::TestExe(const char* file_name,
+ size_t expected_abs_count,
+ size_t expected_rel_count) const {
+ std::string file1 = FileContents(file_name);
+
+ scoped_ptr<courgette::DisassemblerElf32X86> disassembler(
+ new courgette::DisassemblerElf32X86(file1.c_str(), file1.length()));
+
+ bool can_parse_header = disassembler->ParseHeader();
+ EXPECT_TRUE(can_parse_header);
+ EXPECT_TRUE(disassembler->ok());
+
+ // The length of the disassembled value will be slightly smaller than the
+ // real file, since trailing debug info is not included
+ EXPECT_EQ(file1.length(), disassembler->length());
+
+ const uint8* offset_p = disassembler->OffsetToPointer(0);
+ EXPECT_EQ(reinterpret_cast<const void*>(file1.c_str()),
+ reinterpret_cast<const void*>(offset_p));
+ EXPECT_EQ(0x7F, offset_p[0]);
+ EXPECT_EQ('E', offset_p[1]);
+ EXPECT_EQ('L', offset_p[2]);
+ EXPECT_EQ('F', offset_p[3]);
+
+ courgette::AssemblyProgram* program = new courgette::AssemblyProgram();
+
+ EXPECT_TRUE(disassembler->Disassemble(program));
+
+ EXPECT_EQ(disassembler->Abs32Locations().size(), expected_abs_count);
+ EXPECT_EQ(disassembler->Rel32Locations().size(), expected_rel_count);
+
+ // Prove that none of the rel32 RVAs overlap with abs32 RVAs
+ std::set<courgette::RVA> abs(disassembler->Abs32Locations().begin(),
+ disassembler->Abs32Locations().end());
+ std::set<courgette::RVA> rel(disassembler->Rel32Locations().begin(),
+ disassembler->Rel32Locations().end());
+ for (std::vector<courgette::RVA>::iterator rel32 =
+ disassembler->Rel32Locations().begin();
+ rel32 != disassembler->Rel32Locations().end();
+ rel32++) {
+ EXPECT_TRUE(abs.find(*rel32) == abs.end());
+ }
+
+ for (std::vector<courgette::RVA>::iterator abs32 =
+ disassembler->Abs32Locations().begin();
+ abs32 != disassembler->Abs32Locations().end();
+ abs32++) {
+ EXPECT_TRUE(rel.find(*abs32) == rel.end());
+ }
+ delete program;
+}
+
+TEST_F(DisassemblerElf32X86Test, All) {
+ TestExe("elf-32-1", 200, 3441);
+}
diff --git a/courgette/disassembler_win32_x86.cc b/courgette/disassembler_win32_x86.cc
index d09d67d..39cb695 100644
--- a/courgette/disassembler_win32_x86.cc
+++ b/courgette/disassembler_win32_x86.cc
@@ -562,7 +562,7 @@ CheckBool DisassemblerWin32X86::ParseFileRegion(
// actually be anywhere. Make sure we skip it because we will regenerate it
// during assembly.
if (current_rva == relocs_start_rva) {
- ok = program->EmitMakeRelocsInstruction();
+ ok = program->EmitPeRelocsInstruction();
if (!ok)
break;
uint32 relocs_size = base_relocation_table().size_;
diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc
index 90f5cd6..20f0e16 100644
--- a/courgette/encode_decode_unittest.cc
+++ b/courgette/encode_decode_unittest.cc
@@ -8,20 +8,20 @@
class EncodeDecodeTest : public BaseTest {
public:
- void TestExe(const char *) const;
+ void TestAssembleToStreamDisassemble(std::string file,
+ size_t expected_encoded_lenth) const;
};
-void EncodeDecodeTest::TestExe(const char* file_name) const {
- // Test top-level Courgette API for converting an a file to a binary
- // assembly representation and back.
- std::string file1 = FileContents(file_name);
-
- const void* original_buffer = file1.c_str();
- size_t original_length = file1.size();
+void EncodeDecodeTest::TestAssembleToStreamDisassemble(
+ std::string file,
+ size_t expected_encoded_lenth) const {
+ const void* original_buffer = file.c_str();
+ size_t original_length = file.length();
courgette::AssemblyProgram* program = NULL;
const courgette::Status parse_status =
- courgette::ParseDetectedExecutable(original_buffer, original_length,
+ courgette::ParseDetectedExecutable(original_buffer,
+ original_length,
&program);
EXPECT_EQ(courgette::C_OK, parse_status);
@@ -45,7 +45,7 @@ void EncodeDecodeTest::TestExe(const char* file_name) const {
const void* buffer = sink.Buffer();
size_t length = sink.Length();
- EXPECT_EQ(971850U, length);
+ EXPECT_EQ(expected_encoded_lenth, length);
courgette::SourceStreamSet sources;
bool can_get_source_streams = sources.Init(buffer, length);
@@ -68,7 +68,12 @@ void EncodeDecodeTest::TestExe(const char* file_name) const {
DeleteEncodedProgram(encoded2);
}
+TEST_F(EncodeDecodeTest, PE) {
+ std::string file = FileContents("setup1.exe");
+ TestAssembleToStreamDisassemble(file, 971850);
+}
-TEST_F(EncodeDecodeTest, All) {
- TestExe("setup1.exe");
+TEST_F(EncodeDecodeTest, Elf_Small) {
+ std::string file = FileContents("elf-32-1");
+ TestAssembleToStreamDisassemble(file, 135988);
}
diff --git a/courgette/encoded_program.cc b/courgette/encoded_program.cc
index a675dc2..b5e7310 100644
--- a/courgette/encoded_program.cc
+++ b/courgette/encoded_program.cc
@@ -16,6 +16,7 @@
#include "base/utf_string_conversions.h"
#include "courgette/courgette.h"
#include "courgette/streams.h"
+#include "courgette/types_elf.h"
namespace courgette {
@@ -241,8 +242,12 @@ CheckBool EncodedProgram::AddRel32(int label_index) {
return ops_.push_back(REL32) && rel32_ix_.push_back(label_index);
}
-CheckBool EncodedProgram::AddMakeRelocs() {
- return ops_.push_back(MAKE_BASE_RELOCATION_TABLE);
+CheckBool EncodedProgram::AddPeMakeRelocs() {
+ return ops_.push_back(MAKE_PE_RELOCATION_TABLE);
+}
+
+CheckBool EncodedProgram::AddElfMakeRelocs() {
+ return ops_.push_back(MAKE_ELF_RELOCATION_TABLE);
}
void EncodedProgram::DebuggingSummary() {
@@ -399,8 +404,9 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) {
RVA current_rva = 0;
- bool pending_base_relocation_table = false;
- SinkStream bytes_following_base_relocation_table;
+ bool pending_pe_relocation_table = false;
+ bool pending_elf_relocation_table = false;
+ SinkStream bytes_following_relocation_table;
SinkStream* output = final_buffer;
@@ -478,16 +484,16 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) {
break;
}
- case MAKE_BASE_RELOCATION_TABLE: {
+ case MAKE_PE_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_base_relocation_table) // Can't have two base relocation
+ if (pending_pe_relocation_table) // Can't have two base relocation
// tables.
return false;
- pending_base_relocation_table = true;
- output = &bytes_following_base_relocation_table;
+ pending_pe_relocation_table = true;
+ output = &bytes_following_relocation_table;
break;
// There is a potential problem *if* the instruction stream contains
// some REL32 relocations following the base relocation and in the same
@@ -498,12 +504,31 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) {
// executable except some padding zero bytes. We could fix this by
// emitting an ORIGIN after the MAKE_BASE_RELOCATION_TABLE.
}
+
+ 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.
+ return false;
+
+ pending_elf_relocation_table = true;
+ output = &bytes_following_relocation_table;
+ break;
+ }
}
}
- if (pending_base_relocation_table) {
- if (!GenerateBaseRelocations(final_buffer) ||
- !final_buffer->Append(&bytes_following_base_relocation_table))
+ if (pending_pe_relocation_table) {
+ if (!GeneratePeRelocations(final_buffer) ||
+ !final_buffer->Append(&bytes_following_relocation_table))
+ return false;
+ }
+
+ if (pending_elf_relocation_table) {
+ if (!GenerateElfRelocations(final_buffer) ||
+ !final_buffer->Append(&bytes_following_relocation_table))
return false;
}
@@ -557,7 +582,7 @@ class RelocBlock {
RelocBlockPOD pod;
};
-CheckBool EncodedProgram::GenerateBaseRelocations(SinkStream* buffer) {
+CheckBool EncodedProgram::GeneratePeRelocations(SinkStream* buffer) {
std::sort(abs32_relocs_.begin(), abs32_relocs_.end());
RelocBlock block;
@@ -577,6 +602,24 @@ CheckBool EncodedProgram::GenerateBaseRelocations(SinkStream* buffer) {
return ok;
}
+CheckBool EncodedProgram::GenerateElfRelocations(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;
+
+ bool ok = true;
+ for (size_t i = 0; ok && i < abs32_relocs_.size(); ++i) {
+ relocation_block.r_offset = abs32_relocs_[i];
+ ok = buffer->Write(&relocation_block, sizeof(Elf32_Rel));
+ }
+
+ printf("Emitting size %ld\n", sizeof(Elf32_Rel) * abs32_relocs_.size());
+
+ return ok;
+}
////////////////////////////////////////////////////////////////////////////////
Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink) {
diff --git a/courgette/encoded_program.h b/courgette/encoded_program.h
index b120353..62f1439 100644
--- a/courgette/encoded_program.h
+++ b/courgette/encoded_program.h
@@ -43,7 +43,8 @@ class EncodedProgram {
CheckBool AddCopy(uint32 count, const void* bytes) WARN_UNUSED_RESULT;
CheckBool AddRel32(int label_index) WARN_UNUSED_RESULT;
CheckBool AddAbs32(int label_index) WARN_UNUSED_RESULT;
- CheckBool AddMakeRelocs() WARN_UNUSED_RESULT;
+ CheckBool AddPeMakeRelocs() WARN_UNUSED_RESULT;
+ CheckBool AddElfMakeRelocs() WARN_UNUSED_RESULT;
// (3) Serialize binary assembly language tables to a set of streams.
CheckBool WriteTo(SinkStreamSet* streams) WARN_UNUSED_RESULT;
@@ -58,16 +59,18 @@ class EncodedProgram {
private:
// Binary assembly language operations.
+ // These are part of the patch format. Reusing an existing value will
+ // break backwards compatibility.
enum OP {
- ORIGIN, // ORIGIN <rva> - set address for subsequent assembly.
- COPY, // COPY <count> <bytes> - copy bytes to output.
- COPY1, // COPY1 <byte> - same as COPY 1 <byte>.
- REL32, // REL32 <index> - emit rel32 encoded reference to address at
- // address table offset <index>
- ABS32, // ABS32 <index> - emit abs32 encoded reference to address at
- // address table offset <index>
- MAKE_BASE_RELOCATION_TABLE, // Emit base relocation table blocks.
- OP_LAST
+ ORIGIN = 0, // ORIGIN <rva> - set address for subsequent assembly.
+ COPY = 1, // COPY <count> <bytes> - copy bytes to output.
+ COPY1 = 2, // COPY1 <byte> - same as COPY 1 <byte>.
+ REL32 = 3, // REL32 <index> - emit rel32 encoded reference to address at
+ // address table offset <index>
+ 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.
};
typedef NoThrowBuffer<RVA> RvaVector;
@@ -76,7 +79,8 @@ class EncodedProgram {
typedef NoThrowBuffer<OP> OPVector;
void DebuggingSummary();
- CheckBool GenerateBaseRelocations(SinkStream *buffer) WARN_UNUSED_RESULT;
+ CheckBool GeneratePeRelocations(SinkStream *buffer) WARN_UNUSED_RESULT;
+ CheckBool GenerateElfRelocations(SinkStream *buffer) WARN_UNUSED_RESULT;
CheckBool DefineLabelCommon(RvaVector*, int, RVA) WARN_UNUSED_RESULT;
void FinishLabelsCommon(RvaVector* addresses);
diff --git a/courgette/encoded_program_fuzz_unittest.cc b/courgette/encoded_program_fuzz_unittest.cc
index fbf8df7..9801fc8 100644
--- a/courgette/encoded_program_fuzz_unittest.cc
+++ b/courgette/encoded_program_fuzz_unittest.cc
@@ -36,7 +36,7 @@ void DecodeFuzzTest::FuzzExe(const char* file_name) const {
std::string file1 = FileContents(file_name);
const void* original_buffer = file1.c_str();
- size_t original_length = file1.size();
+ size_t original_length = file1.length();
courgette::AssemblyProgram* program = NULL;
const courgette::Status parse_status =
@@ -199,6 +199,7 @@ bool DecodeFuzzTest::TryAssemble(const std::string& buffer,
TEST_F(DecodeFuzzTest, All) {
FuzzExe("setup1.exe");
+ FuzzExe("elf-32-1.exe");
}
int main(int argc, char** argv) {
diff --git a/courgette/ensemble_apply.cc b/courgette/ensemble_apply.cc
index d814264..475cdf2 100644
--- a/courgette/ensemble_apply.cc
+++ b/courgette/ensemble_apply.cc
@@ -142,6 +142,9 @@ Status EnsemblePatchApplication::ReadInitialParameters(
case EXE_WIN_32_X86:
patcher = new PatcherX86_32(base_region_);
break;
+ case EXE_ELF_32_X86:
+ patcher = new PatcherX86_32(base_region_);
+ break;
}
if (patcher)
diff --git a/courgette/ensemble_create.cc b/courgette/ensemble_create.cc
index a5674ca9..c098710 100644
--- a/courgette/ensemble_create.cc
+++ b/courgette/ensemble_create.cc
@@ -76,6 +76,15 @@ TransformationPatchGenerator* MakeGenerator(Element* old_element,
EXE_WIN_32_X86);
return generator;
}
+ case EXE_ELF_32_X86: {
+ TransformationPatchGenerator* generator =
+ new PatchGeneratorX86_32(
+ old_element,
+ new_element,
+ new PatcherX86_32(old_element->region()),
+ EXE_ELF_32_X86);
+ return generator;
+ }
}
LOG(WARNING) << "Unexpected Element::Kind " << old_element->kind();
diff --git a/courgette/patch_generator_x86_32.h b/courgette/patch_generator_x86_32.h
index 0e3b0a8..5ac017b 100644
--- a/courgette/patch_generator_x86_32.h
+++ b/courgette/patch_generator_x86_32.h
@@ -17,9 +17,9 @@ namespace courgette {
class PatchGeneratorX86_32 : public TransformationPatchGenerator {
public:
PatchGeneratorX86_32(Element* old_element,
- Element* new_element,
- PatcherX86_32* patcher,
- ExecutableType kind)
+ Element* new_element,
+ PatcherX86_32* patcher,
+ ExecutableType kind)
: TransformationPatchGenerator(old_element, new_element, patcher),
kind_(kind) {
}
diff --git a/courgette/types_elf.h b/courgette/types_elf.h
new file mode 100644
index 0000000..707f481
--- /dev/null
+++ b/courgette/types_elf.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 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_ELF_TYPES_H_
+#define COURGETTE_ELF_TYPES_H_
+
+//
+// This header defines various types from the ELF file spec, but no code
+// related to using them.
+//
+
+typedef uint32 Elf32_Addr; // Unsigned program address
+typedef uint16 Elf32_Half; // Unsigned medium integer
+typedef uint32 Elf32_Off; // Unsigned file offset
+typedef int32 Elf32_Sword; // Signed large integer
+typedef uint32 Elf32_Word; // Unsigned large integer
+
+
+// The header at the top of the file
+struct Elf32_Ehdr {
+ unsigned char e_ident[16];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+};
+
+// values for header->e_type
+enum e_type_values {
+ ET_NONE = 0, // No file type
+ ET_REL = 1, // Relocatable file
+ ET_EXEC = 2, // Executable file
+ ET_DYN = 3, // Shared object file
+ ET_CORE = 4, // Core file
+ ET_LOPROC = 0xff00, // Processor-specific
+ ET_HIPROC = 0xfff // Processor-specific
+};
+
+// values for header->e_machine
+enum e_machine_values {
+ EM_NONE = 0, // No machine
+ EM_386 = 3, // Intel Architecture
+ EM_x86_64 = 62, // Intel x86-64 Architecture
+ // Other values skipped
+};
+
+// A section header in the section header table
+struct Elf32_Shdr {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+};
+
+// Values for the section type field in a section header
+enum sh_type_values {
+ SHT_NULL = 0,
+ SHT_PROGBITS = 1,
+ SHT_SYMTAB = 2,
+ SHT_STRTAB = 3,
+ SHT_RELA = 4,
+ SHT_HASH = 5,
+ SHT_DYNAMIC = 6,
+ SHT_NOTE = 7,
+ SHT_NOBITS = 8,
+ SHT_REL = 9,
+ SHT_SHLIB = 10,
+ SHT_DYNSYM = 11,
+ SHT_LOPROC = 0x70000000,
+ SHT_HIPROC = 0x7fffffff,
+ SHT_LOUSER = 0x80000000,
+ SHT_HIUSER = 0xffffffff,
+};
+
+struct Elf32_Phdr {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+};
+
+// Values for the segment type field in a program segment header
+enum ph_type_values {
+ PT_NULL = 0,
+ PT_LOAD = 1,
+ PT_DYNAMIC = 2,
+ PT_INTERP = 3,
+ PT_NOTE = 4,
+ PT_SHLIB = 5,
+ PT_PHDR = 6,
+ PT_LOPROC = 0x70000000,
+ PT_HIPROC = 0x7fffffff
+};
+
+struct Elf32_Rel {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+};
+
+struct Elf32_Rela {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+};
+
+enum elf32_rel_386_type_values {
+ R_386_NONE = 0,
+ R_386_32 = 1,
+ R_386_PC32 = 2,
+ R_386_GOT32 = 3,
+ R_386_PLT32 = 4,
+ R_386_COPY = 5,
+ R_386_GLOB_DAT = 6,
+ R_386_JMP_SLOT = 7,
+ R_386_RELATIVE = 8,
+ R_386_GOTOFF = 9,
+ R_386_GOTPC = 10,
+ R_386_TLS_TPOFF = 14,
+};
+
+#endif // COURGETTE_ELF_TYPES_H_