diff options
Diffstat (limited to 'courgette')
-rw-r--r-- | courgette/assembly_program.cc | 32 | ||||
-rw-r--r-- | courgette/assembly_program.h | 5 | ||||
-rw-r--r-- | courgette/bsdiff_memory_unittest.cc | 6 | ||||
-rw-r--r-- | courgette/courgette.gyp | 5 | ||||
-rw-r--r-- | courgette/courgette.h | 1 | ||||
-rw-r--r-- | courgette/disassembler.cc | 9 | ||||
-rw-r--r-- | courgette/disassembler.h | 2 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_x86.cc | 602 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_x86.h | 143 | ||||
-rw-r--r-- | courgette/disassembler_elf_32_x86_unittest.cc | 71 | ||||
-rw-r--r-- | courgette/disassembler_win32_x86.cc | 2 | ||||
-rw-r--r-- | courgette/encode_decode_unittest.cc | 29 | ||||
-rw-r--r-- | courgette/encoded_program.cc | 67 | ||||
-rw-r--r-- | courgette/encoded_program.h | 26 | ||||
-rw-r--r-- | courgette/encoded_program_fuzz_unittest.cc | 3 | ||||
-rw-r--r-- | courgette/ensemble_apply.cc | 3 | ||||
-rw-r--r-- | courgette/ensemble_create.cc | 9 | ||||
-rw-r--r-- | courgette/patch_generator_x86_32.h | 6 | ||||
-rw-r--r-- | courgette/types_elf.h | 141 |
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, + ¤t_abs_offset, end_abs_offset, + ¤t_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_ |