aboutsummaryrefslogtreecommitdiff
path: root/disassembler_elf.h
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2021-08-05 16:46:38 +0000
committerCopybara-Service <copybara-worker@google.com>2021-08-05 10:05:02 -0700
commitfa10b05c4854c6d8a603ee47c2a213cbc23f8646 (patch)
tree94ad9d794dedc26bd0e0be4b18511d45026a0b98 /disassembler_elf.h
parent3e1f64d1395c53a730475d930b663d5f6006099e (diff)
downloadzucchini-fa10b05c4854c6d8a603ee47c2a213cbc23f8646.tar.gz
[Zucchini] Add ARM support for ELF files.
This CL enables ARM-ELF (AArch32 and AArch64) support in Zucchini. * Define ARM {AArch32, AArch64}ReferenceType. * Add Rel32Finder{Arm, AArch32, AArch64} (with tests) to use previously-added ARM disassembly code to extract rel32 references. * Add DisassemblerElf{Arm, AArch32, AArch64} to parse ARM ELF files and create reference readers / writers, and reference groups. * For AArch32: Add heuristic detection of ARM vs. Thumb2 mode. * Add IsTargetOffsetInElfSectionList() (with tests) to help ARM reject false positive references. * Add ReferenceBytesMixerElfArm to remove redundant reference target information from bytewise correction data. Bug: 918867 Change-Id: I1e6d3d8b8d174c85a3d44ca6d642b7ff0bd6a6a6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2922822 Commit-Queue: Samuel Huang <huangs@chromium.org> Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org> Cr-Commit-Position: refs/heads/master@{#908913} NOKEYCHECK=True GitOrigin-RevId: 85cc8a596f183487b395a59e80b2f654f241ab2c
Diffstat (limited to 'disassembler_elf.h')
-rw-r--r--disassembler_elf.h193
1 files changed, 191 insertions, 2 deletions
diff --git a/disassembler_elf.h b/disassembler_elf.h
index ffd1690..0bd11a6 100644
--- a/disassembler_elf.h
+++ b/disassembler_elf.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <algorithm>
#include <deque>
#include <memory>
#include <string>
@@ -23,6 +24,44 @@
namespace zucchini {
+struct ArmReferencePool {
+ enum : uint8_t {
+ kPoolReloc,
+ kPoolAbs32,
+ kPoolRel32,
+ };
+};
+
+struct AArch32ReferenceType {
+ enum : uint8_t {
+ kReloc, // kPoolReloc
+
+ kAbs32, // kPoolAbs32
+
+ kRel32_A24, // kPoolRel32
+ kRel32_T8,
+ kRel32_T11,
+ kRel32_T20,
+ kRel32_T24,
+
+ kTypeCount
+ };
+};
+
+struct AArch64ReferenceType {
+ enum : uint8_t {
+ kReloc, // kPoolReloc
+
+ kAbs32, // kPoolAbs32
+
+ kRel32_Immd14, // kPoolRel32
+ kRel32_Immd19,
+ kRel32_Immd26,
+
+ kTypeCount
+ };
+};
+
struct Elf32Traits {
static constexpr Bitness kBitness = kBit32;
static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS32;
@@ -44,6 +83,16 @@ struct Elf32IntelTraits : public Elf32Traits {
using Rel32FinderUse = Rel32FinderX86;
};
+struct ElfAArch32Traits : public Elf32Traits {
+ static constexpr ExecutableType kExeType = kExeTypeElfAArch32;
+ static const char kExeTypeString[];
+ static constexpr elf::MachineArchitecture kMachineValue = elf::EM_ARM;
+ static constexpr uint32_t kRelType = elf::R_ARM_RELATIVE;
+ enum : uint32_t { kVAWidth = 4 };
+ using ArmReferenceType = AArch32ReferenceType;
+ using Rel32FinderUse = Rel32FinderAArch32;
+};
+
struct Elf64Traits {
static constexpr Bitness kBitness = kBit64;
static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS64;
@@ -64,6 +113,39 @@ struct Elf64IntelTraits : public Elf64Traits {
using Rel32FinderUse = Rel32FinderX64;
};
+struct ElfAArch64Traits : public Elf64Traits {
+ static constexpr ExecutableType kExeType = kExeTypeElfAArch64;
+ static const char kExeTypeString[];
+ static constexpr elf::MachineArchitecture kMachineValue = elf::EM_AARCH64;
+ // TODO(huangs): See if R_AARCH64_GLOB_DAT and R_AARCH64_JUMP_SLOT should be
+ // used.
+ static constexpr uint32_t kRelType = elf::R_AARCH64_RELATIVE;
+ enum : uint32_t { kVAWidth = 8 };
+ using ArmReferenceType = AArch64ReferenceType;
+ using Rel32FinderUse = Rel32FinderAArch64;
+};
+
+// Decides whether target |offset| is covered by a section in |sorted_headers|.
+template <class ELF_SHDR>
+bool IsTargetOffsetInElfSectionList(
+ const std::vector<const ELF_SHDR*>& sorted_headers,
+ offset_t offset) {
+ // Use binary search to search in a list of intervals, in a fashion similar to
+ // AddressTranslator::OffsetToUnit().
+ auto comp = [](offset_t offset, const ELF_SHDR* header) -> bool {
+ return offset < header->sh_offset;
+ };
+ auto it = std::upper_bound(sorted_headers.begin(), sorted_headers.end(),
+ offset, comp);
+ if (it == sorted_headers.begin())
+ return false;
+ --it;
+ // Just check offset without worrying about width, since this is a target.
+ // Not using RangeCovers() because |sh_offset| and |sh_size| can be 64-bit.
+ return offset >= (*it)->sh_offset &&
+ offset - (*it)->sh_offset < (*it)->sh_size;
+}
+
// Disassembler for ELF.
template <class TRAITS>
class DisassemblerElf : public Disassembler {
@@ -82,7 +164,7 @@ class DisassemblerElf : public Disassembler {
std::string GetExeTypeString() const override;
std::vector<ReferenceGroup> MakeReferenceGroups() const override = 0;
- // Find/Receive functions that are common among different architectures.
+ // Read/Write functions that are common among different architectures.
std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi);
std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image);
@@ -174,7 +256,7 @@ class DisassemblerElfIntel : public DisassemblerElf<TRAITS> {
void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
void PostProcessRel32() override;
- // Specialized Find/Receive functions.
+ // Specialized Read/Write functions.
std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi);
@@ -189,6 +271,113 @@ class DisassemblerElfIntel : public DisassemblerElf<TRAITS> {
using DisassemblerElfX86 = DisassemblerElfIntel<Elf32IntelTraits>;
using DisassemblerElfX64 = DisassemblerElfIntel<Elf64IntelTraits>;
+// Disassembler for ELF with ARM architectures.
+template <class TRAITS>
+class DisassemblerElfArm : public DisassemblerElf<TRAITS> {
+ public:
+ using Traits = TRAITS;
+ DisassemblerElfArm();
+ DisassemblerElfArm(const DisassemblerElfArm&) = delete;
+ const DisassemblerElfArm& operator=(const DisassemblerElfArm&) = delete;
+ ~DisassemblerElfArm() override;
+
+ // Determines whether target |offset| is in an executable section.
+ bool IsTargetOffsetInExecSection(offset_t offset) const;
+
+ // Creates an architecture-specific Rel32Finder for ParseExecSection.
+ virtual std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
+ const typename Traits::Elf_Shdr& section) = 0;
+
+ // DisassemblerElf:
+ void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
+ void PostProcessRel32() override;
+
+ // Specialized Read/Write functions.
+ std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
+ std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
+
+ protected:
+ // Sorted file offsets of rel32 locations for each rel32 address type.
+ std::deque<offset_t>
+ rel32_locations_table_[Traits::ArmReferenceType::kTypeCount];
+};
+
+// Disassembler for ELF with AArch32 (AKA ARM32).
+class DisassemblerElfAArch32 : public DisassemblerElfArm<ElfAArch32Traits> {
+ public:
+ DisassemblerElfAArch32();
+ DisassemblerElfAArch32(const DisassemblerElfAArch32&) = delete;
+ const DisassemblerElfAArch32& operator=(const DisassemblerElfAArch32&) =
+ delete;
+ ~DisassemblerElfAArch32() override;
+
+ // Disassembler:
+ std::vector<ReferenceGroup> MakeReferenceGroups() const override;
+
+ // DisassemblerElfArm:
+ std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
+ const typename Traits::Elf_Shdr& section) override;
+
+ // Under the naive assumption that an executable section is entirely ARM mode
+ // or THUMB2 mode, this function implements heuristics to distinguish between
+ // the two. Returns true if section is THUMB2 mode; otherwise return false.
+ bool IsExecSectionThumb2(const typename Traits::Elf_Shdr& section) const;
+
+ // Specialized Read/Write functions for different rel32 address types.
+ std::unique_ptr<ReferenceReader> MakeReadRel32A24(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32A24(MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32T8(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32T8(MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32T11(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32T11(MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32T20(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32T20(MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32T24(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32T24(MutableBufferView image);
+};
+
+// Disassembler for ELF with AArch64 (AKA ARM64).
+class DisassemblerElfAArch64 : public DisassemblerElfArm<ElfAArch64Traits> {
+ public:
+ DisassemblerElfAArch64();
+ DisassemblerElfAArch64(const DisassemblerElfAArch64&) = delete;
+ const DisassemblerElfAArch64& operator=(const DisassemblerElfAArch64&) =
+ delete;
+ ~DisassemblerElfAArch64() override;
+
+ // Disassembler:
+ std::vector<ReferenceGroup> MakeReferenceGroups() const override;
+
+ // DisassemblerElfArm:
+ std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
+ const typename Traits::Elf_Shdr& section) override;
+
+ // Specialized Read/Write functions for different rel32 address types.
+ std::unique_ptr<ReferenceReader> MakeReadRel32Immd14(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32Immd14(
+ MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32Immd19(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32Immd19(
+ MutableBufferView image);
+
+ std::unique_ptr<ReferenceReader> MakeReadRel32Immd26(offset_t lower,
+ offset_t upper);
+ std::unique_ptr<ReferenceWriter> MakeWriteRel32Immd26(
+ MutableBufferView image);
+};
+
} // namespace zucchini
#endif // COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_