aboutsummaryrefslogtreecommitdiff
path: root/rel32_finder.cc
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 /rel32_finder.cc
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 'rel32_finder.cc')
-rw-r--r--rel32_finder.cc129
1 files changed, 129 insertions, 0 deletions
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 <typename ADDR_TYPE>
+Rel32FinderArm<ADDR_TYPE>::Rel32FinderArm(ConstBufferView image,
+ const AddressTranslator& translator)
+ : Rel32Finder(image, translator) {}
+
+template <typename ADDR_TYPE>
+Rel32FinderArm<ADDR_TYPE>::~Rel32FinderArm() = default;
+
+template <typename ADDR_TYPE>
+Rel32Finder::NextIterators Rel32FinderArm<ADDR_TYPE>::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 <typename ADDR_TYPE>
+Rel32Finder::NextIterators Rel32FinderArm<ADDR_TYPE>::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<offset_t>(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<offset_t>(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<offset_t>(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