aboutsummaryrefslogtreecommitdiff
path: root/disassembler_elf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'disassembler_elf.cc')
-rw-r--r--disassembler_elf.cc351
1 files changed, 350 insertions, 1 deletions
diff --git a/disassembler_elf.cc b/disassembler_elf.cc
index 9c9ebb8..94dc12a 100644
--- a/disassembler_elf.cc
+++ b/disassembler_elf.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include <algorithm>
#include <utility>
#include "base/logging.h"
@@ -14,6 +13,7 @@
#include "base/numerics/safe_conversions.h"
#include "components/zucchini/abs32_utils.h"
#include "components/zucchini/algorithm.h"
+#include "components/zucchini/arm_utils.h"
#include "components/zucchini/buffer_source.h"
namespace zucchini {
@@ -23,6 +23,9 @@ namespace {
constexpr uint64_t kElfImageBase = 0;
constexpr size_t kSizeBound = 0x7FFF0000;
+// Threshold value for heuristics to detect THUMB2 code.
+constexpr double kAArch32BitCondAlwaysDensityThreshold = 0.4;
+
// Bit fields for JudgeSection() return value.
enum SectionJudgement : int {
// Bit: Section does not invalidate ELF, but may or may not be useful.
@@ -132,6 +135,14 @@ const char Elf32IntelTraits::kExeTypeString[] = "ELF x86";
constexpr elf::MachineArchitecture Elf32IntelTraits::kMachineValue;
constexpr uint32_t Elf32IntelTraits::kRelType;
+/******** ElfAArch32Traits ********/
+
+// static
+constexpr ExecutableType ElfAArch32Traits::kExeType;
+const char ElfAArch32Traits::kExeTypeString[] = "ELF ARM";
+constexpr elf::MachineArchitecture ElfAArch32Traits::kMachineValue;
+constexpr uint32_t ElfAArch32Traits::kRelType;
+
/******** Elf64Traits ********/
// static
@@ -146,6 +157,14 @@ const char Elf64IntelTraits::kExeTypeString[] = "ELF x64";
constexpr elf::MachineArchitecture Elf64IntelTraits::kMachineValue;
constexpr uint32_t Elf64IntelTraits::kRelType;
+/******** ElfAArch64Traits ********/
+
+// static
+constexpr ExecutableType ElfAArch64Traits::kExeType;
+const char ElfAArch64Traits::kExeTypeString[] = "ELF ARM64";
+constexpr elf::MachineArchitecture ElfAArch64Traits::kMachineValue;
+constexpr uint32_t ElfAArch64Traits::kRelType;
+
/******** DisassemblerElf ********/
// static.
@@ -503,4 +522,334 @@ template bool DisassemblerElf<Elf32IntelTraits>::QuickDetect(
template bool DisassemblerElf<Elf64IntelTraits>::QuickDetect(
ConstBufferView image);
+/******** DisassemblerElfArm ********/
+
+template <class Traits>
+DisassemblerElfArm<Traits>::DisassemblerElfArm() = default;
+
+template <class Traits>
+DisassemblerElfArm<Traits>::~DisassemblerElfArm() = default;
+
+template <class Traits>
+bool DisassemblerElfArm<Traits>::IsTargetOffsetInExecSection(
+ offset_t offset) const {
+ // Executable sections can appear in large numbers in .o files and in
+ // pathological cases. Since this function may be called for each reference
+ // candidate, linear search may be too slow (so use binary search).
+ return IsTargetOffsetInElfSectionList(this->exec_headers_, offset);
+}
+
+template <class Traits>
+void DisassemblerElfArm<Traits>::ParseExecSection(
+ const typename Traits::Elf_Shdr& section) {
+ ConstBufferView& image_ = this->image_;
+ const AddressTranslator& translator_ = this->translator_;
+ auto& abs32_locations_ = this->abs32_locations_;
+
+ ConstBufferView region(image_.begin() + section.sh_offset, section.sh_size);
+ Abs32GapFinder gap_finder(image_, region, abs32_locations_, Traits::kVAWidth);
+ std::unique_ptr<typename Traits::Rel32FinderUse> rel_finder =
+ MakeRel32Finder(section);
+ AddressTranslator::RvaToOffsetCache rva_to_offset(translator_);
+ while (gap_finder.FindNext()) {
+ rel_finder->SetRegion(gap_finder.GetGap());
+ while (rel_finder->FindNext()) {
+ auto rel32 = rel_finder->GetRel32();
+ offset_t target_offset = rva_to_offset.Convert(rel32.target_rva);
+ if (target_offset != kInvalidOffset) {
+ // For robustness, reject illegal offsets, which can arise from, e.g.,
+ // misidentify ARM vs. THUMB2 mode, or even misidentifying data as code!
+ if (IsTargetOffsetInExecSection(target_offset)) {
+ rel_finder->Accept();
+ rel32_locations_table_[rel32.type].push_back(rel32.location);
+ }
+ }
+ }
+ }
+}
+
+template <class Traits>
+void DisassemblerElfArm<Traits>::PostProcessRel32() {
+ for (int type = 0; type < AArch32Rel32Translator::NUM_ADDR_TYPE; ++type) {
+ std::sort(rel32_locations_table_[type].begin(),
+ rel32_locations_table_[type].end());
+ rel32_locations_table_[type].shrink_to_fit();
+ }
+}
+
+template <class Traits>
+std::unique_ptr<ReferenceReader> DisassemblerElfArm<Traits>::MakeReadAbs32(
+ offset_t lo,
+ offset_t hi) {
+ // TODO(huangs): Reconcile the use of Win32-specific classes in ARM code!
+ Abs32RvaExtractorWin32 abs_rva_extractor(this->image_,
+ AbsoluteAddress(Traits::kBitness, 0),
+ this->abs32_locations_, lo, hi);
+ return std::make_unique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
+ this->translator_);
+}
+
+template <class Traits>
+std::unique_ptr<ReferenceWriter> DisassemblerElfArm<Traits>::MakeWriteAbs32(
+ MutableBufferView image) {
+ return std::make_unique<Abs32WriterWin32>(
+ image, AbsoluteAddress(Traits::kBitness, 0), this->translator_);
+}
+
+/******** DisassemblerElfAArch32 ********/
+
+DisassemblerElfAArch32::DisassemblerElfAArch32() = default;
+DisassemblerElfAArch32::~DisassemblerElfAArch32() = default;
+
+std::vector<ReferenceGroup> DisassemblerElfAArch32::MakeReferenceGroups()
+ const {
+ return {
+ {ReferenceTypeTraits{sizeof(Traits::Elf_Rel::r_offset),
+ TypeTag(AArch32ReferenceType::kReloc),
+ PoolTag(ArmReferencePool::kPoolReloc)},
+ &DisassemblerElfAArch32::MakeReadRelocs,
+ &DisassemblerElfAArch32::MakeWriteRelocs},
+ {ReferenceTypeTraits{Traits::kVAWidth,
+ TypeTag(AArch32ReferenceType::kAbs32),
+ PoolTag(ArmReferencePool::kPoolAbs32)},
+ &DisassemblerElfAArch32::MakeReadAbs32,
+ &DisassemblerElfAArch32::MakeWriteAbs32},
+ {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_A24),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch32::MakeReadRel32A24,
+ &DisassemblerElfAArch32::MakeWriteRel32A24},
+ {ReferenceTypeTraits{2, TypeTag(AArch32ReferenceType::kRel32_T8),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch32::MakeReadRel32T8,
+ &DisassemblerElfAArch32::MakeWriteRel32T8},
+ {ReferenceTypeTraits{2, TypeTag(AArch32ReferenceType::kRel32_T11),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch32::MakeReadRel32T11,
+ &DisassemblerElfAArch32::MakeWriteRel32T11},
+ {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_T20),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch32::MakeReadRel32T20,
+ &DisassemblerElfAArch32::MakeWriteRel32T20},
+ {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_T24),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch32::MakeReadRel32T24,
+ &DisassemblerElfAArch32::MakeWriteRel32T24},
+ };
+}
+
+std::unique_ptr<DisassemblerElfAArch32::Traits::Rel32FinderUse>
+DisassemblerElfAArch32::MakeRel32Finder(
+ const typename Traits::Elf_Shdr& section) {
+ return std::make_unique<Rel32FinderAArch32>(image_, translator_,
+ IsExecSectionThumb2(section));
+}
+
+bool DisassemblerElfAArch32::IsExecSectionThumb2(
+ const typename Traits::Elf_Shdr& section) const {
+ // ARM mode requires 4-byte alignment.
+ if (section.sh_addr % 4 != 0 || section.sh_size % 4 != 0)
+ return true;
+ const uint8_t* first = image_.begin() + section.sh_offset;
+ const uint8_t* end = first + section.sh_size;
+ // Each instruction in 32-bit ARM (little-endian) looks like
+ // ?? ?? ?? X?,
+ // where X specifies conditional execution. X = 0xE represents AL = "ALways
+ // execute", and tends to appear very often. We use this as our main indicator
+ // to discern 32-bit ARM mode from THUMB2 mode.
+ size_t num = 0;
+ size_t den = 0;
+ for (const uint8_t* cur = first; cur < end; cur += 4) {
+ // |cur[3]| is within bounds because |end - cur| is a multiple of 4.
+ uint8_t maybe_cond = cur[3] & 0xF0;
+ if (maybe_cond == 0xE0)
+ ++num;
+ ++den;
+ }
+
+ if (den > 0) {
+ LOG(INFO) << "Section scan: " << num << " / " << den << " => "
+ << base::StringPrintf("%.2f", num * 100.0 / den) << "%";
+ }
+ return num < den * kAArch32BitCondAlwaysDensityThreshold;
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch32::MakeReadRel32A24(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_A24>>(
+ translator_, image_,
+ rel32_locations_table_[AArch32Rel32Translator::ADDR_A24], lower, upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch32::MakeWriteRel32A24(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch32Rel32Translator::AddrTraits_A24>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch32::MakeReadRel32T8(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_T8>>(
+ translator_, image_,
+ rel32_locations_table_[AArch32Rel32Translator::ADDR_T8], lower, upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch32::MakeWriteRel32T8(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T8>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch32::MakeReadRel32T11(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_T11>>(
+ translator_, image_,
+ rel32_locations_table_[AArch32Rel32Translator::ADDR_T11], lower, upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch32::MakeWriteRel32T11(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T11>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch32::MakeReadRel32T20(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_T20>>(
+ translator_, image_,
+ rel32_locations_table_[AArch32Rel32Translator::ADDR_T20], lower, upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch32::MakeWriteRel32T20(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T20>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch32::MakeReadRel32T24(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_T24>>(
+ translator_, image_,
+ rel32_locations_table_[AArch32Rel32Translator::ADDR_T24], lower, upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch32::MakeWriteRel32T24(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T24>>(translator_,
+ image);
+}
+
+/******** DisassemblerElfAArch64 ********/
+
+DisassemblerElfAArch64::DisassemblerElfAArch64() = default;
+
+DisassemblerElfAArch64::~DisassemblerElfAArch64() = default;
+
+std::vector<ReferenceGroup> DisassemblerElfAArch64::MakeReferenceGroups()
+ const {
+ return {
+ {ReferenceTypeTraits{sizeof(Traits::Elf_Rel::r_offset),
+ TypeTag(AArch64ReferenceType::kReloc),
+ PoolTag(ArmReferencePool::kPoolReloc)},
+ &DisassemblerElfAArch64::MakeReadRelocs,
+ &DisassemblerElfAArch64::MakeWriteRelocs},
+ {ReferenceTypeTraits{Traits::kVAWidth,
+ TypeTag(AArch64ReferenceType::kAbs32),
+ PoolTag(ArmReferencePool::kPoolAbs32)},
+ &DisassemblerElfAArch64::MakeReadAbs32,
+ &DisassemblerElfAArch64::MakeWriteAbs32},
+ {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd14),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch64::MakeReadRel32Immd14,
+ &DisassemblerElfAArch64::MakeWriteRel32Immd14},
+ {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd19),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch64::MakeReadRel32Immd19,
+ &DisassemblerElfAArch64::MakeWriteRel32Immd19},
+ {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd26),
+ PoolTag(ArmReferencePool::kPoolRel32)},
+ &DisassemblerElfAArch64::MakeReadRel32Immd26,
+ &DisassemblerElfAArch64::MakeWriteRel32Immd26},
+ };
+}
+
+std::unique_ptr<DisassemblerElfAArch64::Traits::Rel32FinderUse>
+DisassemblerElfAArch64::MakeRel32Finder(
+ const typename Traits::Elf_Shdr& section) {
+ return std::make_unique<Rel32FinderAArch64>(image_, translator_);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch64::MakeReadRel32Immd14(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd14>>(
+ translator_, this->image_,
+ rel32_locations_table_[AArch64Rel32Translator::ADDR_IMMD14], lower,
+ upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch64::MakeWriteRel32Immd14(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd14>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch64::MakeReadRel32Immd19(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd19>>(
+ translator_, this->image_,
+ rel32_locations_table_[AArch64Rel32Translator::ADDR_IMMD19], lower,
+ upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch64::MakeWriteRel32Immd19(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd19>>(translator_,
+ image);
+}
+
+std::unique_ptr<ReferenceReader> DisassemblerElfAArch64::MakeReadRel32Immd26(
+ offset_t lower,
+ offset_t upper) {
+ return std::make_unique<
+ Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd26>>(
+ translator_, this->image_,
+ rel32_locations_table_[AArch64Rel32Translator::ADDR_IMMD26], lower,
+ upper);
+}
+
+std::unique_ptr<ReferenceWriter> DisassemblerElfAArch64::MakeWriteRel32Immd26(
+ MutableBufferView image) {
+ return std::make_unique<
+ Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd26>>(translator_,
+ image);
+}
+
+// Explicit instantiation for supported classes.
+template class DisassemblerElfArm<ElfAArch32Traits>;
+template class DisassemblerElfArm<ElfAArch64Traits>;
+template bool DisassemblerElf<ElfAArch32Traits>::QuickDetect(
+ ConstBufferView image);
+template bool DisassemblerElf<ElfAArch64Traits>::QuickDetect(
+ ConstBufferView image);
+
} // namespace zucchini