summaryrefslogtreecommitdiffstats
path: root/courgette
diff options
context:
space:
mode:
authordgarrett@chromium.org <dgarrett@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-07 22:49:15 +0000
committerdgarrett@chromium.org <dgarrett@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-07 22:49:15 +0000
commit88da5078df0e51dc1c56dac1aa92608a53a03803 (patch)
tree93c6b467379da5dd3ef243e3f0e3bc353b4f3333 /courgette
parent2ca59863a57ed182b9b5a3c89b6212c10e94ec06 (diff)
downloadchromium_src-88da5078df0e51dc1c56dac1aa92608a53a03803.zip
chromium_src-88da5078df0e51dc1c56dac1aa92608a53a03803.tar.gz
chromium_src-88da5078df0e51dc1c56dac1aa92608a53a03803.tar.bz2
Add Elf 32 Support to Courgette.
This change takes advantage of recent refactoring and adds support for Elf X86 32 executables to courgette. It should have no effect on handling of Windows PE executables. We have planned ahead to be able to restrict the code size of the courgette library in different cases to reduce patcher sizes, but this change does not yet take advantage of that (all platforms are supported everywhere). Also, the patcher class currently contains a very small amount of Elf/PE specific code for recreating relocation tables that cannot (currently) be compiled out. BUG=chromium-os:22149 TEST=Please verify that Chrome/Chromium patches can still be generated and work. Also, please see how much the updater executable which is downloaded to users has changed in size since R16. Review URL: http://codereview.chromium.org/8428009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108929 0039d316-1c4b-4281-b951-d872f2087c98
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_