diff options
author | Samuel Huang <huangs@chromium.org> | 2021-08-05 16:46:38 +0000 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2021-08-05 10:05:02 -0700 |
commit | fa10b05c4854c6d8a603ee47c2a213cbc23f8646 (patch) | |
tree | 94ad9d794dedc26bd0e0be4b18511d45026a0b98 /disassembler_elf.h | |
parent | 3e1f64d1395c53a730475d930b663d5f6006099e (diff) | |
download | zucchini-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.h | 193 |
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_ |