From fa10b05c4854c6d8a603ee47c2a213cbc23f8646 Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Thu, 5 Aug 2021 16:46:38 +0000 Subject: [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 Reviewed-by: Etienne Pierre-Doray Cr-Commit-Position: refs/heads/master@{#908913} NOKEYCHECK=True GitOrigin-RevId: 85cc8a596f183487b395a59e80b2f654f241ab2c --- rel32_finder.cc | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'rel32_finder.cc') diff --git a/rel32_finder.cc b/rel32_finder.cc index ccb26f4..1ad8910 100644 --- a/rel32_finder.cc +++ b/rel32_finder.cc @@ -162,4 +162,133 @@ Rel32Finder::NextIterators Rel32FinderX64::Scan(ConstBufferView region) { return {nullptr, nullptr}; } +/******** Rel32FinderArm ********/ + +template +Rel32FinderArm::Rel32FinderArm(ConstBufferView image, + const AddressTranslator& translator) + : Rel32Finder(image, translator) {} + +template +Rel32FinderArm::~Rel32FinderArm() = default; + +template +Rel32Finder::NextIterators Rel32FinderArm::SetResult( + Result&& result, + ConstBufferView::const_iterator cursor, + int instr_size) { + rel32_ = result; + return {cursor + instr_size, cursor + instr_size}; +} + +// SetResult() for end of scan. +template +Rel32Finder::NextIterators Rel32FinderArm::SetEmptyResult() { + rel32_ = {kInvalidOffset, kInvalidOffset, ADDR_TYPE::ADDR_NONE}; + return {nullptr, nullptr}; +} + +/******** Rel32FinderAArch32 ********/ + +Rel32FinderAArch32::Rel32FinderAArch32(ConstBufferView image, + const AddressTranslator& translator, + bool is_thumb2) + : Rel32FinderArm(image, translator), is_thumb2_(is_thumb2) {} + +Rel32FinderAArch32::~Rel32FinderAArch32() = default; + +Rel32Finder::NextIterators Rel32FinderAArch32::ScanA32(ConstBufferView region) { + // Guard against alignment potentially causing |cursor > region.end()|. + if (region.size() < 4) + return SetEmptyResult(); + ConstBufferView::const_iterator cursor = region.begin(); + cursor += IncrementForAlignCeil4(cursor - image_.begin()); + for (; region.end() - cursor >= 4; cursor += 4) { + offset_t offset = base::checked_cast(cursor - image_.begin()); + AArch32Rel32Translator translator; + rva_t instr_rva = offset_to_rva_.Convert(offset); + uint32_t code32 = translator.FetchArmCode32(image_, offset); + rva_t target_rva = kInvalidRva; + if (translator.ReadA24(instr_rva, code32, &target_rva)) { + return SetResult({offset, target_rva, AArch32Rel32Translator::ADDR_A24}, + cursor, 4); + } + } + return SetEmptyResult(); +} + +Rel32Finder::NextIterators Rel32FinderAArch32::ScanT32(ConstBufferView region) { + // Guard against alignment potentially causing |cursor > region.end()|. + if (region.size() < 2) + return SetEmptyResult(); + ConstBufferView::const_iterator cursor = region.begin(); + cursor += IncrementForAlignCeil2(cursor - image_.begin()); + while (region.end() - cursor >= 2) { + offset_t offset = base::checked_cast(cursor - image_.begin()); + AArch32Rel32Translator translator; + AArch32Rel32Translator::AddrType type = AArch32Rel32Translator::ADDR_NONE; + rva_t instr_rva = offset_to_rva_.Convert(offset); + uint16_t code16 = translator.FetchThumb2Code16(image_, offset); + int instr_size = GetThumb2InstructionSize(code16); + rva_t target_rva = kInvalidRva; + if (instr_size == 2) { // 16-bit THUMB2 instruction. + if (translator.ReadT8(instr_rva, code16, &target_rva)) + type = AArch32Rel32Translator::ADDR_T8; + else if (translator.ReadT11(instr_rva, code16, &target_rva)) + type = AArch32Rel32Translator::ADDR_T11; + } else { // |instr_size == 4|: 32-bit THUMB2 instruction. + if (region.end() - cursor >= 4) { + uint32_t code32 = translator.FetchThumb2Code32(image_, offset); + if (translator.ReadT20(instr_rva, code32, &target_rva)) + type = AArch32Rel32Translator::ADDR_T20; + else if (translator.ReadT24(instr_rva, code32, &target_rva)) + type = AArch32Rel32Translator::ADDR_T24; + } + } + if (type != AArch32Rel32Translator::ADDR_NONE) + return SetResult({offset, target_rva, type}, cursor, instr_size); + cursor += instr_size; + } + return SetEmptyResult(); +} + +Rel32Finder::NextIterators Rel32FinderAArch32::Scan(ConstBufferView region) { + return is_thumb2_ ? ScanT32(region) : ScanA32(region); +} + +/******** Rel32FinderAArch64 ********/ + +Rel32FinderAArch64::Rel32FinderAArch64(ConstBufferView image, + const AddressTranslator& translator) + : Rel32FinderArm(image, translator) {} + +Rel32FinderAArch64::~Rel32FinderAArch64() = default; + +Rel32Finder::NextIterators Rel32FinderAArch64::Scan(ConstBufferView region) { + // Guard against alignment potentially causing |cursor > region.end()|. + if (region.size() < 4) + return SetEmptyResult(); + ConstBufferView::const_iterator cursor = region.begin(); + cursor += IncrementForAlignCeil4(cursor - image_.begin()); + for (; region.end() - cursor >= 4; cursor += 4) { + offset_t offset = base::checked_cast(cursor - image_.begin()); + // For simplicity we assume RVA fits within 32-bits. + AArch64Rel32Translator translator; + AArch64Rel32Translator::AddrType type = AArch64Rel32Translator::ADDR_NONE; + rva_t instr_rva = offset_to_rva_.Convert(offset); + uint32_t code32 = translator.FetchCode32(image_, offset); + rva_t target_rva = kInvalidRva; + if (translator.ReadImmd14(instr_rva, code32, &target_rva)) { + type = AArch64Rel32Translator::ADDR_IMMD14; + } else if (translator.ReadImmd19(instr_rva, code32, &target_rva)) { + type = AArch64Rel32Translator::ADDR_IMMD19; + } else if (translator.ReadImmd26(instr_rva, code32, &target_rva)) { + type = AArch64Rel32Translator::ADDR_IMMD26; + } + if (type != AArch64Rel32Translator::ADDR_NONE) + return SetResult({offset, target_rva, type}, cursor, 4); + } + return SetEmptyResult(); +} + } // namespace zucchini -- cgit v1.2.3