diff options
-rw-r--r-- | BUILD.gn | 4 | ||||
-rw-r--r-- | buffer_view.h | 18 | ||||
-rw-r--r-- | buffer_view_unittest.cc | 20 | ||||
-rw-r--r-- | reloc_elf.cc | 162 | ||||
-rw-r--r-- | reloc_elf.h | 102 | ||||
-rw-r--r-- | reloc_elf_unittest.cc | 127 | ||||
-rw-r--r-- | reloc_win32_unittest.cc | 19 | ||||
-rw-r--r-- | test_utils.h | 15 | ||||
-rw-r--r-- | type_elf.h | 252 |
9 files changed, 698 insertions, 21 deletions
@@ -78,6 +78,8 @@ static_library("zucchini_lib") { "rel32_finder.h", "rel32_utils.cc", "rel32_utils.h", + "reloc_elf.cc", + "reloc_elf.h", "reloc_win32.cc", "reloc_win32.h", "suffix_array.h", @@ -86,6 +88,7 @@ static_library("zucchini_lib") { "targets_affinity.cc", "targets_affinity.h", "type_dex.h", + "type_elf.h", "type_win_pe.h", "typed_value.h", "zucchini.h", @@ -169,6 +172,7 @@ test("zucchini_unittests") { "reference_set_unittest.cc", "rel32_finder_unittest.cc", "rel32_utils_unittest.cc", + "reloc_elf_unittest.cc", "reloc_win32_unittest.cc", "suffix_array_unittest.cc", "target_pool_unittest.cc", diff --git a/buffer_view.h b/buffer_view.h index 66925c4..727ebd1 100644 --- a/buffer_view.h +++ b/buffer_view.h @@ -131,16 +131,30 @@ class BufferViewBase { template <class U> const U& read(size_type pos) const { - CHECK_LE(pos + sizeof(U), size()); + // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). + CHECK_LE(sizeof(U), size()); + CHECK_LE(pos, size() - sizeof(U)); return *reinterpret_cast<const U*>(begin() + pos); } template <class U> void write(size_type pos, const U& value) { - CHECK_LE(pos + sizeof(U), size()); + // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). + CHECK_LE(sizeof(U), size()); + CHECK_LE(pos, size() - sizeof(U)); *reinterpret_cast<U*>(begin() + pos) = value; } + // Returns a mutable reference to an object type U whose raw storage starts + // at location |pos|. + template <class U> + U& modify(size_type pos) { + // TODO(huangs): Use can_access<U>(pos) after fixing can_access(). + CHECK_LE(sizeof(U), size()); + CHECK_LE(pos, size() - sizeof(U)); + return *reinterpret_cast<U*>(begin() + pos); + } + template <class U> bool can_access(size_type pos) const { return pos < size() && size() - pos >= sizeof(U); diff --git a/buffer_view_unittest.cc b/buffer_view_unittest.cc index 7df34b2..30170d7 100644 --- a/buffer_view_unittest.cc +++ b/buffer_view_unittest.cc @@ -130,6 +130,26 @@ TEST_F(BufferViewTest, Write) { EXPECT_DEATH(buffer.write<uint32_t>(7, 0xFFFFFFFF), ""); } +TEST_F(BufferViewTest, Modify) { + struct TestStruct { + uint32_t a; + uint32_t b; + }; + + MutableBufferView buffer(bytes_.data(), bytes_.size()); + + buffer.modify<TestStruct>(0).a = 0x01234567; + buffer.modify<TestStruct>(0).b = 0x89ABCDEF; + EXPECT_EQ(ParseHexString("67 45 23 01 EF CD AB 89 10 00"), + std::vector<uint8_t>(buffer.begin(), buffer.end())); + + buffer.modify<uint8_t>(9); + EXPECT_DEATH(buffer.modify<uint8_t>(10), ""); + + buffer.modify<uint32_t>(6); + EXPECT_DEATH(buffer.modify<uint32_t>(7), ""); +} + TEST_F(BufferViewTest, CanAccess) { MutableBufferView buffer(bytes_.data(), bytes_.size()); EXPECT_TRUE(buffer.can_access<uint32_t>(0)); diff --git a/reloc_elf.cc b/reloc_elf.cc new file mode 100644 index 0000000..6a32184 --- /dev/null +++ b/reloc_elf.cc @@ -0,0 +1,162 @@ +// Copyright 2018 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 "components/zucchini/reloc_elf.h" + +#include <algorithm> +#include <tuple> +#include <utility> + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "components/zucchini/algorithm.h" + +namespace zucchini { + +/******** RelocReaderElf ********/ + +RelocReaderElf::RelocReaderElf( + ConstBufferView image, + Bitness bitness, + const std::vector<SectionDimensionsElf>& reloc_section_dims, + uint32_t rel_type, + offset_t lo, + offset_t hi, + const AddressTranslator& translator) + : image_(image), + bitness_(bitness), + rel_type_(rel_type), + reloc_section_dimensions_(reloc_section_dims), + hi_(hi), + target_rva_to_offset_(translator) { + DCHECK(bitness_ == kBit32 || bitness_ == kBit64); + + // Find the relocation section at or right before |lo|. + cur_section_dimensions_ = std::upper_bound( + reloc_section_dimensions_.begin(), reloc_section_dimensions_.end(), lo); + if (cur_section_dimensions_ != reloc_section_dimensions_.begin()) + --cur_section_dimensions_; + + // |lo| and |hi_| do not cut across a reloc reference (e.g., + // Elf_Rel::r_offset), but may cut across a reloc struct (e.g. Elf_Rel)! + // GetNext() emits all reloc references in |[lo, hi_)|, but needs to examine + // the entire reloc struct for context. Knowing that |r_offset| is the first + // entry in a reloc struct, |cursor_| and |hi_| are adjusted by the following: + // - If |lo| is in a reloc section, then |cursor_| is chosen, as |lo| aligned + // up to the next reloc struct, to exclude reloc struct that |lo| may cut + // across. + // - If |hi_| is in a reloc section, then align it up, to include reloc struct + // that |hi_| may cut across. + cursor_ = + base::checked_cast<offset_t>(cur_section_dimensions_->region.offset); + if (cursor_ < lo) + cursor_ += + AlignCeil<offset_t>(lo - cursor_, cur_section_dimensions_->entry_size); + + auto end_section = std::upper_bound(reloc_section_dimensions_.begin(), + reloc_section_dimensions_.end(), hi_); + if (end_section != reloc_section_dimensions_.begin()) { + --end_section; + if (hi_ - end_section->region.offset < end_section->region.size) { + offset_t end_region_offset = + base::checked_cast<offset_t>(end_section->region.offset); + hi_ = end_region_offset + AlignCeil<offset_t>(hi_ - end_region_offset, + end_section->entry_size); + } + } +} + +RelocReaderElf::~RelocReaderElf() = default; + +rva_t RelocReaderElf::GetRelocationTarget(elf::Elf32_Rel rel) const { + // The least significant byte of |rel.r_info| is the type. The other 3 bytes + // store the symbol, which we ignore. + uint32_t type = static_cast<uint32_t>(rel.r_info & 0xFF); + if (type == rel_type_) + return rel.r_offset; + return kInvalidRva; +} + +rva_t RelocReaderElf::GetRelocationTarget(elf::Elf64_Rel rel) const { + // The least significant 4 bytes of |rel.r_info| is the type. The other 4 + // bytes store the symbol, which we ignore. + uint32_t type = static_cast<uint32_t>(rel.r_info & 0xFFFFFFFF); + if (type == rel_type_) { + // Assume |rel.r_offset| fits within 32-bit integer. + if ((rel.r_offset & 0xFFFFFFFF) == rel.r_offset) + return static_cast<rva_t>(rel.r_offset); + // Otherwise output warning. + LOG(WARNING) << "Warning: Skipping r_offset whose value exceeds 32-bits."; + } + return kInvalidRva; +} + +base::Optional<Reference> RelocReaderElf::GetNext() { + offset_t cur_entry_size = cur_section_dimensions_->entry_size; + offset_t cur_section_dimensions_end = + base::checked_cast<offset_t>(cur_section_dimensions_->region.hi()); + + for (; cursor_ + cur_entry_size <= hi_; cursor_ += cur_entry_size) { + while (cursor_ >= cur_section_dimensions_end) { + ++cur_section_dimensions_; + if (cur_section_dimensions_ == reloc_section_dimensions_.end()) + return base::nullopt; + cur_entry_size = cur_section_dimensions_->entry_size; + cursor_ = + base::checked_cast<offset_t>(cur_section_dimensions_->region.offset); + if (cursor_ + cur_entry_size > hi_) + return base::nullopt; + cur_section_dimensions_end = + base::checked_cast<offset_t>(cur_section_dimensions_->region.hi()); + } + rva_t target_rva = kInvalidRva; + // TODO(huangs): Fix RELA sections: Need to process |r_addend|. + switch (bitness_) { + case kBit32: + target_rva = GetRelocationTarget(image_.read<elf::Elf32_Rel>(cursor_)); + break; + case kBit64: + target_rva = GetRelocationTarget(image_.read<elf::Elf64_Rel>(cursor_)); + break; + } + if (target_rva == kInvalidRva) + continue; + // |target| will be used to obtain abs32 references, so we must ensure that + // it lies inside |image_|. + offset_t target = target_rva_to_offset_.Convert(target_rva); + if (target == kInvalidOffset || !image_.covers({target, sizeof(offset_t)})) + continue; + offset_t location = cursor_; + cursor_ += cur_entry_size; + return Reference{location, target}; + } + return base::nullopt; +} + +/******** RelocWriterElf ********/ + +RelocWriterElf::RelocWriterElf(MutableBufferView image, + Bitness bitness, + const AddressTranslator& translator) + : image_(image), bitness_(bitness), target_offset_to_rva_(translator) { + DCHECK(bitness_ == kBit32 || bitness_ == kBit64); +} + +RelocWriterElf::~RelocWriterElf() = default; + +void RelocWriterElf::PutNext(Reference ref) { + switch (bitness_) { + case kBit32: + image_.modify<elf::Elf32_Rel>(ref.location).r_offset = + target_offset_to_rva_.Convert(ref.target); + break; + case kBit64: + image_.modify<elf::Elf64_Rel>(ref.location).r_offset = + target_offset_to_rva_.Convert(ref.target); + break; + } + // Leave |reloc.r_info| alone. +} + +} // namespace zucchini diff --git a/reloc_elf.h b/reloc_elf.h new file mode 100644 index 0000000..1b5ba11 --- /dev/null +++ b/reloc_elf.h @@ -0,0 +1,102 @@ +// Copyright 2018 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 COMPONENTS_ZUCCHINI_RELOC_ELF_H_ +#define COMPONENTS_ZUCCHINI_RELOC_ELF_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <vector> + +#include "base/optional.h" +#include "components/zucchini/address_translator.h" +#include "components/zucchini/buffer_source.h" +#include "components/zucchini/buffer_view.h" +#include "components/zucchini/image_utils.h" +#include "components/zucchini/type_elf.h" + +namespace zucchini { + +// Section dimensions for ELF files, to store relevant dimensions data from +// Elf32_Shdr and Elf64_Shdr, while reducing code duplication from templates. +struct SectionDimensionsElf { + SectionDimensionsElf() = default; + + template <class Elf_Shdr> + explicit SectionDimensionsElf(const Elf_Shdr& section) + : region(BufferRegion{base::checked_cast<size_t>(section.sh_offset), + base::checked_cast<size_t>(section.sh_size)}), + entry_size(base::checked_cast<offset_t>(section.sh_entsize)) {} + + friend bool operator<(const SectionDimensionsElf& a, + const SectionDimensionsElf& b) { + return a.region.offset < b.region.offset; + } + + friend bool operator<(offset_t offset, const SectionDimensionsElf& section) { + return offset < section.region.offset; + } + + BufferRegion region; + offset_t entry_size; // Varies across REL / RELA sections. +}; + +// A Generator to visit all reloc structs located in [|lo|, |hi|) (excluding +// truncated strct at |lo| but inlcuding truncated struct at |hi|), and emit +// valid References with |rel_type|. This implements a nested loop unrolled into +// a generator: the outer loop has |cur_section_dimensions_| visiting +// |reloc_section_dims| (sorted by |region.offset|), and the inner loop has +// |cursor_| visiting successive reloc structs within |cur_section_dimensions_|. +class RelocReaderElf : public ReferenceReader { + public: + RelocReaderElf( + ConstBufferView image, + Bitness bitness, + const std::vector<SectionDimensionsElf>& reloc_section_dimensions, + uint32_t rel_type, + offset_t lo, + offset_t hi, + const AddressTranslator& translator); + ~RelocReaderElf() override; + + // If |rel| contains |r_offset| for |rel_type_|, return the RVA. Otherwise + // return |kInvalidRva|. These also handle Elf*_Rela, by using the fact that + // Elf*_Rel is a prefix of Elf*_Rela. + rva_t GetRelocationTarget(elf::Elf32_Rel rel) const; + rva_t GetRelocationTarget(elf::Elf64_Rel rel) const; + + // ReferenceReader: + base::Optional<Reference> GetNext() override; + + private: + const ConstBufferView image_; + const Bitness bitness_; + const uint32_t rel_type_; + const std::vector<SectionDimensionsElf>& reloc_section_dimensions_; + std::vector<SectionDimensionsElf>::const_iterator cur_section_dimensions_; + offset_t hi_; + offset_t cursor_; + AddressTranslator::RvaToOffsetCache target_rva_to_offset_; +}; + +class RelocWriterElf : public ReferenceWriter { + public: + RelocWriterElf(MutableBufferView image, + Bitness bitness, + const AddressTranslator& translator); + ~RelocWriterElf() override; + + // ReferenceWriter: + void PutNext(Reference ref) override; + + private: + MutableBufferView image_; + const Bitness bitness_; + AddressTranslator::OffsetToRvaCache target_offset_to_rva_; +}; + +} // namespace zucchini + +#endif // COMPONENTS_ZUCCHINI_RELOC_ELF_H_ diff --git a/reloc_elf_unittest.cc b/reloc_elf_unittest.cc new file mode 100644 index 0000000..104694e --- /dev/null +++ b/reloc_elf_unittest.cc @@ -0,0 +1,127 @@ +// Copyright 2018 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 "components/zucchini/reloc_elf.h" + +#include <stdint.h> + +#include <algorithm> +#include <memory> +#include <vector> + +#include "base/numerics/safe_conversions.h" +#include "components/zucchini/address_translator.h" +#include "components/zucchini/algorithm.h" +#include "components/zucchini/image_utils.h" +#include "components/zucchini/test_utils.h" +#include "components/zucchini/type_elf.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace zucchini { + +namespace { + +template <class Elf_Shdr> +SectionDimensionsElf MakeSectionDimensions(const BufferRegion& region, + offset_t entry_size) { + using sh_offset_t = decltype(Elf_Shdr::sh_offset); + using sh_size_t = decltype(Elf_Shdr::sh_size); + using sh_entsize_t = decltype(Elf_Shdr::sh_entsize); + return SectionDimensionsElf{Elf_Shdr{ + 0, // sh_name + 0, // sh_type + 0, // sh_flags + 0, // sh_addr + // sh_offset + base::checked_cast<sh_offset_t>(region.offset), + // sh_size + base::checked_cast<sh_size_t>(region.size), + 0, // sh_link + 0, // sh_info + 0, // sh_addralign + // sh_entsize + base::checked_cast<sh_entsize_t>(entry_size), + }}; +} + +} // namespace + +TEST(RelocElfTest, ReadWrite32) { + // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset. + constexpr rva_t kBaseRva = 0x40000; + std::vector<uint8_t> image_data(0x3000, 0xFF); + // "C0 10 04 00 08 00 00 00" represents + // (r_sym, r_type, r_offset) = (0x000000, 0x08, 0x000410C0). + // r_type = 0x08 = R_386_RELATIVE, and under this r_offset is an RVA + // 0x000410C0. Zucchini does not care about r_sym. + std::vector<uint8_t> reloc_data1 = ParseHexString( + "C0 10 04 00 08 00 00 00 " // R_386_RELATIVE. + "F8 10 04 00 08 AB CD EF " // R_386_RELATIVE. + "00 10 04 00 00 AB CD EF " // R_386_NONE. + "00 10 04 00 07 AB CD EF" // R_386_JMP_SLOT. + ); + BufferRegion reloc_region1 = {0x600, reloc_data1.size()}; + std::copy(reloc_data1.begin(), reloc_data1.end(), + image_data.begin() + reloc_region1.lo()); + + std::vector<uint8_t> reloc_data2 = ParseHexString( + "BC 20 04 00 08 00 00 00 " // R_386_RELATIVE. + "A0 20 04 00 08 AB CD EF" // R_386_RELATIVE. + ); + BufferRegion reloc_region2 = {0x620, reloc_data2.size()}; + std::copy(reloc_data2.begin(), reloc_data2.end(), + image_data.begin() + reloc_region2.lo()); + + ConstBufferView image = {image_data.data(), image_data.size()}; + offset_t image_size = base::checked_cast<offset_t>(image_data.size()); + + AddressTranslator translator; + translator.Initialize({{0, image_size, kBaseRva, image_size}}); + + std::vector<SectionDimensionsElf> section_dimensions{ + MakeSectionDimensions<elf::Elf32_Shdr>(reloc_region1, 8), + MakeSectionDimensions<elf::Elf32_Shdr>(reloc_region2, 8)}; + + // Make RelocReaderElf. + auto reader = std::make_unique<RelocReaderElf>( + image, kBit32, section_dimensions, elf::R_386_RELATIVE, 0, image_size, + translator); + + // Read all references and check. + std::vector<Reference> refs; + for (base::Optional<Reference> ref = reader->GetNext(); ref.has_value(); + ref = reader->GetNext()) { + refs.push_back(ref.value()); + } + // Only R_386_RELATIVE references are extracted. Targets are translated from + // address (e.g., 0x000420BC) to offset (e.g., 0x20BC). + std::vector<Reference> exp_refs{ + {0x600, 0x10C0}, {0x608, 0x10F8}, {0x620, 0x20BC}, {0x628, 0x20A0}}; + EXPECT_EQ(exp_refs, refs); + + // Write reference, extract bytes and check. + MutableBufferView mutable_image(&image_data[0], image_data.size()); + auto writer = + std::make_unique<RelocWriterElf>(mutable_image, kBit32, translator); + + writer->PutNext({0x608, 0x1F83}); + std::vector<uint8_t> exp_reloc_data1 = ParseHexString( + "C0 10 04 00 08 00 00 00 " // R_386_RELATIVE. + "83 1F 04 00 08 AB CD EF " // R_386_RELATIVE (address modified). + "00 10 04 00 00 AB CD EF " // R_386_NONE. + "00 10 04 00 07 AB CD EF " // R_386_JMP_SLOT. + ); + EXPECT_EQ(exp_reloc_data1, + Sub(image_data, reloc_region1.lo(), reloc_region1.hi())); + + writer->PutNext({0x628, 0x2950}); + std::vector<uint8_t> exp_reloc_data2 = ParseHexString( + "BC 20 04 00 08 00 00 00 " // R_386_RELATIVE. + "50 29 04 00 08 AB CD EF" // R_386_RELATIVE (address modified). + ); + EXPECT_EQ(exp_reloc_data2, + Sub(image_data, reloc_region2.lo(), reloc_region2.hi())); +} + +} // namespace zucchini diff --git a/reloc_win32_unittest.cc b/reloc_win32_unittest.cc index ca9bbe6..eaf55e1 100644 --- a/reloc_win32_unittest.cc +++ b/reloc_win32_unittest.cc @@ -23,25 +23,6 @@ namespace zucchini { -namespace { - -// Returns a vector that's the contatenation of two vectors of the same type. -// Elements are copied by value. -template <class T> -std::vector<T> Cat(const std::vector<T>& a, const std::vector<T>& b) { - std::vector<T> ret(a); - ret.insert(ret.end(), b.begin(), b.end()); - return ret; -} - -// Returns a subvector of a vector. Elements are copied by value. -template <class T> -std::vector<T> Sub(const std::vector<T>& a, size_t lo, size_t hi) { - return std::vector<T>(a.begin() + lo, a.begin() + hi); -} - -} // namespace - class RelocUtilsWin32Test : public testing::Test { protected: using Units = std::vector<RelocUnitWin32>; diff --git a/test_utils.h b/test_utils.h index 7ed735d..e922343 100644 --- a/test_utils.h +++ b/test_utils.h @@ -15,6 +15,21 @@ namespace zucchini { // Parses space-separated list of byte hex values into list. std::vector<uint8_t> ParseHexString(const std::string& hex_string); +// Returns a vector that's the contatenation of two vectors of the same type. +// Elements are copied by value. +template <class T> +std::vector<T> Cat(const std::vector<T>& a, const std::vector<T>& b) { + std::vector<T> ret(a); + ret.insert(ret.end(), b.begin(), b.end()); + return ret; +} + +// Returns a subvector of a vector. Elements are copied by value. +template <class T> +std::vector<T> Sub(const std::vector<T>& a, size_t lo, size_t hi) { + return std::vector<T>(a.begin() + lo, a.begin() + hi); +} + } // namespace zucchini #endif // COMPONENTS_ZUCCHINI_TEST_UTILS_H_ diff --git a/type_elf.h b/type_elf.h new file mode 100644 index 0000000..99dcba2 --- /dev/null +++ b/type_elf.h @@ -0,0 +1,252 @@ +// Copyright 2018 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 COMPONENTS_ZUCCHINI_TYPE_ELF_H_ +#define COMPONENTS_ZUCCHINI_TYPE_ELF_H_ + +#include <stdint.h> + +namespace zucchini { + +// Structures and constants taken from linux/elf.h and following identical +// layout. This is used for parsing of Executable and Linkable Format (ELF). +namespace elf { +// Supported by MSVC, g++, and clang++. Ensures no gaps in packing. +#pragma pack(push, 1) + +// This header defines various types from the ELF file spec, but no code +// related to using them. + +typedef uint32_t Elf32_Addr; // Unsigned program address. +typedef uint16_t Elf32_Half; // Unsigned medium integer. +typedef uint32_t Elf32_Off; // Unsigned file offset. +typedef int32_t Elf32_Sword; // Signed large integer. +typedef uint32_t Elf32_Word; // Unsigned large integer. + +typedef uint64_t Elf64_Addr; // Unsigned program address. +typedef uint16_t Elf64_Half; // Unsigned medium integer. +typedef uint64_t Elf64_Off; // Unsigned file offset. +typedef int32_t Elf64_Sword; // Signed large integer. +typedef uint32_t Elf64_Word; // Unsigned large integer. +typedef int64_t Elf64_Sxword; // Signed extra large integer. +typedef uint64_t Elf64_Xword; // Unsigned extra 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; +}; + +struct Elf64_Ehdr { + unsigned char e_ident[16]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_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 = 0xFFFF // Processor-specific +}; + +// Values for header->e_machine. +enum e_machine_values { + EM_NONE = 0, // No machine. + EM_386 = 3, // Intel Architecture. + EM_ARM = 40, // ARM Architecture. + EM_X86_64 = 62, // Intel x86-64 Architecture. + EM_AARCH64 = 183, // ARM Architecture, 64-bit. + // 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; +}; + +struct Elf64_Shdr { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword 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_INIT_ARRAY = 14, + SHT_FINI_ARRAY = 15, + SHT_LOPROC = 0x70000000, + SHT_HIPROC = 0x7FFFFFFF, + SHT_LOUSER = 0x80000000, + SHT_HIUSER = 0xFFFFFFFF +}; + +enum sh_flag_masks { + SHF_WRITE = 1 << 0, + SHF_ALLOC = 1 << 1, + SHF_EXECINSTR = 1 << 2, +}; + +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; +}; + +struct Elf64_Phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword 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 Elf64_Rel { + Elf64_Addr r_offset; + Elf64_Xword r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword 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, +}; + +enum elf32_rel_x86_64_type_values { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_GOT32 = 3, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_16 = 12, + R_X86_64_PC16 = 13, + R_X86_64_8 = 14, + R_X86_64_PC8 = 15, +}; + +enum elf32_rel_arm_type_values { + R_ARM_RELATIVE = 23, +}; + +enum elf64_rel_aarch64_type_values { + R_AARCH64_GLOB_DAT = 0x401, + R_AARCH64_JUMP_SLOT = 0x402, + R_AARCH64_RELATIVE = 0x403, +}; + +#pragma pack(pop) + +} // namespace elf +} // namespace zucchini + +#endif // COMPONENTS_ZUCCHINI_TYPE_ELF_H_ |