aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILD.gn4
-rw-r--r--buffer_view.h18
-rw-r--r--buffer_view_unittest.cc20
-rw-r--r--reloc_elf.cc162
-rw-r--r--reloc_elf.h102
-rw-r--r--reloc_elf_unittest.cc127
-rw-r--r--reloc_win32_unittest.cc19
-rw-r--r--test_utils.h15
-rw-r--r--type_elf.h252
9 files changed, 698 insertions, 21 deletions
diff --git a/BUILD.gn b/BUILD.gn
index c871d9d..4e289e3 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -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_