aboutsummaryrefslogtreecommitdiff
path: root/rel32_finder_unittest.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_unittest.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_unittest.cc')
-rw-r--r--rel32_finder_unittest.cc333
1 files changed, 303 insertions, 30 deletions
diff --git a/rel32_finder_unittest.cc b/rel32_finder_unittest.cc
index 69ea42a..7e4a21e 100644
--- a/rel32_finder_unittest.cc
+++ b/rel32_finder_unittest.cc
@@ -15,8 +15,11 @@
#include "base/check_op.h"
#include "base/format_macros.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
+#include "components/zucchini/arm_utils.h"
#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/disassembler_elf.h"
#include "components/zucchini/image_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -42,23 +45,23 @@ TEST(Abs32GapFinderTest, All) {
std::string out_str;
while (gap_finder.FindNext()) {
ConstBufferView gap = gap_finder.GetGap();
- size_t lo = static_cast<size_t>(gap.begin() - image.begin());
- size_t hi = static_cast<size_t>(gap.end() - image.begin());
+ size_t lo = base::checked_cast<size_t>(gap.begin() - image.begin());
+ size_t hi = base::checked_cast<size_t>(gap.end() - image.begin());
out_str.append(base::StringPrintf("[%" PRIuS ",%" PRIuS ")", lo, hi));
}
return out_str;
};
// Empty regions yield empty segments.
- EXPECT_EQ("", run_test(0, 0, std::vector<offset_t>(), 4));
- EXPECT_EQ("", run_test(9, 9, std::vector<offset_t>(), 4));
+ EXPECT_EQ("", run_test(0, 0, {}, 4));
+ EXPECT_EQ("", run_test(9, 9, {}, 4));
EXPECT_EQ("", run_test(8, 8, {8}, 4));
EXPECT_EQ("", run_test(8, 8, {0, 12}, 4));
// If no abs32 locations exist then the segment is the main range.
- EXPECT_EQ("[0,99)", run_test(0, 99, std::vector<offset_t>(), 4));
- EXPECT_EQ("[20,21)", run_test(20, 21, std::vector<offset_t>(), 4));
- EXPECT_EQ("[51,55)", run_test(51, 55, std::vector<offset_t>(), 4));
+ EXPECT_EQ("[0,99)", run_test(0, 99, {}, 4));
+ EXPECT_EQ("[20,21)", run_test(20, 21, {}, 4));
+ EXPECT_EQ("[51,55)", run_test(51, 55, {}, 4));
// abs32 locations found near start of main range.
EXPECT_EQ("[10,20)", run_test(10, 20, {5}, 4));
@@ -132,8 +135,8 @@ class TestRel32Finder : public Rel32Finder {
AddressTranslator GetTrivialTranslator(size_t size) {
AddressTranslator translator;
EXPECT_EQ(AddressTranslator::kSuccess,
- translator.Initialize({{0, static_cast<offset_t>(size), 0U,
- static_cast<rva_t>(size)}}));
+ translator.Initialize({{0, base::checked_cast<offset_t>(size), 0U,
+ base::checked_cast<rva_t>(size)}}));
return translator;
}
@@ -220,8 +223,8 @@ constexpr uint8_t kDataX86[] = {
};
// Abs32 locations corresponding to |kDataX86|, with width = 4.
-constexpr uint8_t kAbs32X86[] = {0x08, 0x17, 0x26, 0x2A,
- 0x40, 0x51, 0x5F, 0x63};
+constexpr offset_t kAbs32X86[] = {0x08, 0x17, 0x26, 0x2A,
+ 0x40, 0x51, 0x5F, 0x63};
} // namespace
@@ -256,28 +259,28 @@ TEST(Rel32FinderX86Test, FindNext) {
TEST(Rel32FinderX86Test, Integrated) {
// Truncated form of Rel32FinderIntel::Result.
- typedef std::pair<offset_t, rva_t> TruncatedResults;
+ using TruncatedResults = std::pair<offset_t, rva_t>;
ConstBufferView image =
ConstBufferView::FromRange(std::begin(kDataX86), std::end(kDataX86));
std::vector<offset_t> abs32_locations(std::begin(kAbs32X86),
std::end(kAbs32X86));
- std::vector<TruncatedResults> rel32_results;
+ std::vector<TruncatedResults> results;
- Abs32GapFinder gap_finder(image, image, abs32_locations, 4U);
+ Abs32GapFinder gap_finder(image, image, abs32_locations,
+ DisassemblerElfX86::Traits::kVAWidth);
AddressTranslator translator(GetTrivialTranslator(image.size()));
Rel32FinderX86 rel_finder(image, translator);
while (gap_finder.FindNext()) {
- auto gap = gap_finder.GetGap();
rel_finder.SetRegion(gap_finder.GetGap());
while (rel_finder.FindNext()) {
auto rel32 = rel_finder.GetRel32();
- rel32_results.emplace_back(
- TruncatedResults{rel32.location, rel32.target_rva});
+ rel_finder.Accept();
+ results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva});
}
}
- std::vector<TruncatedResults> expected_rel32_results = {
+ std::vector<TruncatedResults> expected_results = {
{0x04, 0x08},
/* {0x09, 0x0D}, */ {0x0F, 0x13},
/* {0x15, 0x19}, */ /*{0x1B, 0x1F}, */
@@ -288,7 +291,7 @@ TEST(Rel32FinderX86Test, Integrated) {
/* {0x51, 0x55}, */ {0x57, 0x5B},
/* {0x5D, 0x61}, */ /* {0x63, 0x67}, */ {0x69, 0x6D},
};
- EXPECT_EQ(expected_rel32_results, rel32_results);
+ EXPECT_EQ(expected_results, results);
}
TEST(Rel32FinderX86Test, Accept) {
@@ -367,8 +370,8 @@ constexpr uint8_t kDataX64[] = {
};
// Abs32 locations corresponding to |kDataX64|, with width = 8.
-constexpr uint8_t kAbs32X64[] = {0x0C, 0x1F, 0x33, 0x3B, 0x49,
- 0x6A, 0x99, 0xB3, 0xCC};
+constexpr offset_t kAbs32X64[] = {0x0C, 0x1F, 0x33, 0x3B, 0x49,
+ 0x6A, 0x99, 0xB3, 0xCC};
} // namespace
@@ -420,31 +423,31 @@ TEST(Rel32FinderX64Test, FindNext) {
TEST(Rel32FinderX64Test, Integrated) {
// Truncated form of Rel32FinderIntel::Result.
- typedef std::pair<offset_t, rva_t> TruncatedResults;
+ using TruncatedResults = std::pair<offset_t, rva_t>;
ConstBufferView image =
ConstBufferView::FromRange(std::begin(kDataX64), std::end(kDataX64));
std::vector<offset_t> abs32_locations(std::begin(kAbs32X64),
std::end(kAbs32X64));
- std::vector<TruncatedResults> rel32_results;
+ std::vector<TruncatedResults> results;
- Abs32GapFinder gap_finder(image, image, abs32_locations, 8U);
+ Abs32GapFinder gap_finder(image, image, abs32_locations,
+ DisassemblerElfX64::Traits::kVAWidth);
AddressTranslator translator(GetTrivialTranslator(image.size()));
Rel32FinderX64 rel_finder(image, translator);
while (gap_finder.FindNext()) {
- auto gap = gap_finder.GetGap();
rel_finder.SetRegion(gap_finder.GetGap());
while (rel_finder.FindNext()) {
auto rel32 = rel_finder.GetRel32();
- rel32_results.emplace_back(
- TruncatedResults{rel32.location, rel32.target_rva});
+ rel_finder.Accept();
+ results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva});
}
}
- std::vector<TruncatedResults> expected_rel32_results = {
+ std::vector<TruncatedResults> expected_results = {
{0x04, 0x08},
/* {0x09, 0x0D}, */
- /*{0x0F, 0x13}, */ /* {0x15, 0x19}, */ {0x1B, 0x1F},
+ /* {0x0F, 0x13}, */ /* {0x15, 0x19}, */ {0x1B, 0x1F},
/* {0x21, 0x25}, */ /* {0x27, 0x2B}, */ {0x2D, 0x31},
/* {0x33, 0x37}, */ /* {0x39, 0x3D}, */
/* {0x3F, 0x43}, */ {0x45, 0x49},
@@ -464,7 +467,277 @@ TEST(Rel32FinderX64Test, Integrated) {
/* {0xCC, 0xD0}, */ /* {0xD3, 0xD7}, */ {0xDA, 0xDE},
{0xE1, 0xE5},
};
- EXPECT_EQ(expected_rel32_results, rel32_results);
+ EXPECT_EQ(expected_results, results);
+}
+
+namespace {
+
+// Runs the ARM rel32 extraction (nested) loop on |image| using |rel32_finder|,
+// given |abs32_locations| for abs32 references each having |abs32_width|.
+// Returns the list of extracted references.
+template <class REL32_FINDER>
+std::vector<typename REL32_FINDER::Result> ArmExtractRel32(
+ ConstBufferView image,
+ const std::vector<offset_t>& abs32_locations,
+ int abs32_width,
+ REL32_FINDER&& rel32_finder) {
+ std::vector<typename REL32_FINDER::Result> results;
+ Abs32GapFinder gap_finder(image, image, abs32_locations, abs32_width);
+ while (gap_finder.FindNext()) {
+ rel32_finder.SetRegion(gap_finder.GetGap());
+ while (rel32_finder.FindNext()) {
+ typename REL32_FINDER::Result rel32 = rel32_finder.GetRel32();
+ rel32_finder.Accept();
+ results.emplace_back(rel32);
+ }
+ }
+ return results;
+}
+
+} // namespace
+
+namespace {
+
+// AArch32 ARM mode test data. (x) and +x entries are covered by abs32
+// references (if used), which have width = 4.
+constexpr uint8_t kDataAarch32ArmMode[] = {
+ 0x00, 0x01, 0x02, 0xEA, // 00: B 00080408 ; B encoding A1
+ 0x00, 0x01, (0x02), +0xEA, // 04: B 0008040C ; B encoding A1
+ +0x00, +0x01, 0x02, 0xEA, // 08: B 00080410 ; B encoding A1
+ 0x00, 0x01, 0x02, 0xEA, // 0C: B 00080414 ; B encoding A1
+ 0x00, 0x01, 0x02, (0xEA), // 10: B 00080418 ; B encoding A1
+ +0x00, +0x01, +0x02, 0xEA, // 14: B 0008041C ; B encoding A1
+ 0x00, 0x01, 0x02, 0xEA, // 18: B 00080420 ; B encoding A1
+};
+
+// Abs32 locations corresponding to |kDataAarch32ArmMode|, with width = 4.
+constexpr offset_t kAbs32Aarch32ArmMode[] = {0x6, 0x13};
+
+} // namespace
+
+TEST(Rel32FinderAArch32Test, IntegratedArmModeWithoutAbs32) {
+ using AddrType = AArch32Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch32::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x80408, AddrType::ADDR_A24}, {0x04, 0x8040C, AddrType::ADDR_A24},
+ {0x08, 0x80410, AddrType::ADDR_A24}, {0x0C, 0x80414, AddrType::ADDR_A24},
+ {0x10, 0x80418, AddrType::ADDR_A24}, {0x14, 0x8041C, AddrType::ADDR_A24},
+ {0x18, 0x80420, AddrType::ADDR_A24},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(
+ std::begin(kDataAarch32ArmMode), std::end(kDataAarch32ArmMode));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ false);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, /* abs32_locations */ {}, DisassemblerElfAArch32::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
+}
+
+TEST(Rel32FinderAArch32Test, IntegratedArmModeWithAbs32) {
+ using AddrType = AArch32Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch32::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x80408, AddrType::ADDR_A24},
+ /* {0x04, 0x8040C, AddrType::ADDR_A24}, */
+ /* {0x08, 0x80410, AddrType::ADDR_A24}, */
+ {0x0C, 0x80414, AddrType::ADDR_A24},
+ /* {0x10, 0x80418, AddrType::ADDR_A24}, */
+ /* {0x14, 0x8041C, AddrType::ADDR_A24}, */
+ {0x18, 0x80420, AddrType::ADDR_A24},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(
+ std::begin(kDataAarch32ArmMode), std::end(kDataAarch32ArmMode));
+ std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32ArmMode),
+ std::end(kAbs32Aarch32ArmMode));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ false);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, abs32_locations, DisassemblerElfAArch32::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
+}
+
+namespace {
+
+// AArch32 THUMB2 mode test data. (x) and +x entries are covered by abs32
+// references (if used), which have width = 4.
+constexpr uint8_t kDataAarch32Thumb2Mode[] = {
+ 0x00, 0xDE, // 00: B.AL 00000004 ; B encoding T1
+ 0x00, 0xDE, // 02: B.AL 00000006 ; B encoding T1
+ 0x00, (0xDE), // 04: B.AL 00000008 ; B encoding T1
+ +0x00, +0xDE, // 06: B.AL 0000000A ; B encoding T1
+ +0x00, 0xE0, // 08: B 0000000C ; B encoding T2
+ 0x00, 0xE0, // 0A: B 0000000E ; B encoding T2
+ 0x00, 0xE0, // 0C: B 00000010 ; B encoding T2
+ (0x00), +0xE0, // 0E: B 00000012 ; B encoding T2
+ +0x00, +0xF0, 0x00, 0x80, // 10: B 00000014 ; B encoding T3
+ 0x00, 0xF0, 0x00, 0x80, // 14: B 00000018 ; B encoding T3
+ (0x00), +0xF0, +0x00, +0x80, // 18: B 0000001C ; B encoding T3
+ 0x00, 0xF0, 0x00, 0x80, // 1C: B 00000020 ; B encoding T3
+ 0x00, 0xF0, 0x00, 0xB8, // 20: B 00000024 ; B encoding T4
+ 0x00, 0xF0, 0x00, (0xB8), // 24: B 00000028 ; B encoding T4
+ +0xFE, +0xDE, // 28: B.AL 00000028 ; B encoding T1
+ +0x00, 0xF0, 0x00, 0xF8, // 2A: BL 0000002E ; BL encoding T1
+ 0x00, 0xF0, 0x00, 0xE8, // 2E: BLX 00000030 ; BLX encoding T2
+ 0x00, 0x0B, // 32: NOP
+ 0x00, 0xF0, 0x00, 0xE8, // 34: BLX 00000038 ; BLX encoding T2
+ 0x00, 0xF0, 0x00, 0xB8, // 38: B 0000003C ; B encoding T4
+};
+
+// Abs32 locations corresponding to |kDataAarch32Thumb2Mode|, with width = 4.
+constexpr offset_t kAbs32Aarch32Thumb2Mode[] = {0x05, 0x0E, 0x18, 0x27};
+
+} // namespace
+
+TEST(Rel32FinderAArch32Test, IntegratedThumb2ModeWithoutAbs32) {
+ using AddrType = AArch32Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch32::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x04, AddrType::ADDR_T8}, {0x02, 0x06, AddrType::ADDR_T8},
+ {0x04, 0x08, AddrType::ADDR_T8}, {0x06, 0x0A, AddrType::ADDR_T8},
+ {0x08, 0x0C, AddrType::ADDR_T11}, {0x0A, 0x0E, AddrType::ADDR_T11},
+ {0x0C, 0x10, AddrType::ADDR_T11}, {0x0E, 0x12, AddrType::ADDR_T11},
+ {0x10, 0x14, AddrType::ADDR_T20}, {0x14, 0x18, AddrType::ADDR_T20},
+ {0x18, 0x1C, AddrType::ADDR_T20}, {0x1C, 0x20, AddrType::ADDR_T20},
+ {0x20, 0x24, AddrType::ADDR_T24}, {0x24, 0x28, AddrType::ADDR_T24},
+ {0x28, 0x28, AddrType::ADDR_T8}, {0x2A, 0x2E, AddrType::ADDR_T24},
+ {0x2E, 0x30, AddrType::ADDR_T24}, {0x34, 0x38, AddrType::ADDR_T24},
+ {0x38, 0x3C, AddrType::ADDR_T24},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(
+ std::begin(kDataAarch32Thumb2Mode), std::end(kDataAarch32Thumb2Mode));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ true);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, /* abs32_locations */ {}, DisassemblerElfAArch32::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
+}
+
+TEST(Rel32FinderAArch32Test, IntegratedThumb2ModeWithAbs32) {
+ using AddrType = AArch32Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch32::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x04, AddrType::ADDR_T8},
+ {0x02, 0x06, AddrType::ADDR_T8},
+ /* {0x04, 0x08, AddrType::ADDR_T8}, */
+ /* {0x06, 0x0A, AddrType::ADDR_T8}, */
+ /* {0x08, 0x0C, AddrType::ADDR_T11}, */
+ {0x0A, 0x0E, AddrType::ADDR_T11},
+ {0x0C, 0x10, AddrType::ADDR_T11},
+ /* {0x0E, 0x12, AddrType::ADDR_T11}, */
+ /* {0x10, 0x14, AddrType::ADDR_T20}, */
+ {0x14, 0x18, AddrType::ADDR_T20},
+ /* {0x18, 0x1C, AddrType::ADDR_T20}, */
+ {0x1C, 0x20, AddrType::ADDR_T20},
+ {0x20, 0x24, AddrType::ADDR_T24},
+ /* {0x24, 0x28, AddrType::ADDR_T24}, */
+ /* {0x28, 0x28, AddrType::ADDR_T8}, */
+ /* {0x2A, 0x2E, AddrType::ADDR_T24}, */
+ // Abs32 reference 0x27 disrupts alignment, and THUMB2 disassembly starts
+ // at 0x2C, causing the following to be excluded!
+ /* {0x2E, 0x30, AddrType::ADDR_T24}, */
+ {0x34, 0x38, AddrType::ADDR_T24},
+ {0x38, 0x3C, AddrType::ADDR_T24},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(
+ std::begin(kDataAarch32Thumb2Mode), std::end(kDataAarch32Thumb2Mode));
+ std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32Thumb2Mode),
+ std::end(kAbs32Aarch32Thumb2Mode));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ true);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, abs32_locations, DisassemblerElfAArch32::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
+}
+
+namespace {
+
+// AArch32 THUMB2 mode test data. (x) and +x entries are covered by abs32
+// references (if used), which have width = 8.
+constexpr uint8_t kDataAarch64[] = {
+ 0x0E, 0x00, 0x00, 0x36, // 00: TBZ X0,#0,00000000 ; Immd14
+ 0x0E, 0x00, 0x00, (0x36), // 04: TBZ X0,#0,00000004 ; Immd14
+ +0x0E, +0x00, +0x00, +0x36, // 08: TBZ X0,#0,00000008 ; Immd14
+ +0x0E, +0x00, +0x00, 0x54, // 0C: B.AL 0000000C ; Immd19
+ 0x0E, 0x00, 0x00, 0x54, // 10: B.AL 00000010 ; Immd19
+ (0x0E), +0x00, +0x00, +0x54, // 14: B.AL 00000014 ; Immd19
+ +0x00, +0x00, +0x00, +0x94, // 18: BL 00000018 ; Immd26
+ 0x00, 0x00, 0x00, 0x14, // 1C: B 0000001C ; Immd26
+ 0x00, 0x00, 0x00, 0x94, // 20: BL 00000020 ; Immd26
+ 0x00, 0x00, 0x00, 0x14, // 24: B 00000024 ; Immd26
+};
+
+// Abs32 locations corresponding to |kDataAarch64|, with width = 8.
+constexpr offset_t kAbs32Aarch64[] = {0x07, 0x14};
+
+} // namespace
+
+TEST(Rel32FinderAArch64Test, IntegratedWithoutAbs32) {
+ using AddrType = AArch64Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch64::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x00, AddrType::ADDR_IMMD14}, {0x04, 0x04, AddrType::ADDR_IMMD14},
+ {0x08, 0x08, AddrType::ADDR_IMMD14}, {0x0C, 0x0C, AddrType::ADDR_IMMD19},
+ {0x10, 0x10, AddrType::ADDR_IMMD19}, {0x14, 0x14, AddrType::ADDR_IMMD19},
+ {0x18, 0x18, AddrType::ADDR_IMMD26}, {0x1C, 0x1C, AddrType::ADDR_IMMD26},
+ {0x20, 0x20, AddrType::ADDR_IMMD26}, {0x24, 0x24, AddrType::ADDR_IMMD26},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(std::begin(kDataAarch64),
+ std::end(kDataAarch64));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch64 rel32_finder(image, translator);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, /* abs32_locations */ {}, DisassemblerElfAArch64::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
+}
+
+TEST(Rel32FinderAArch64Test, IntegratedWithAbs32) {
+ using AddrType = AArch64Rel32Translator::AddrType;
+ using Result = Rel32FinderAArch64::Result;
+ std::vector<Result> expected_results = {
+ {0x00, 0x00, AddrType::ADDR_IMMD14},
+ /* {0x04, 0x04, AddrType::ADDR_IMMD14}, */
+ /* {0x08, 0x08, AddrType::ADDR_IMMD14}, */
+ /* {0x0C, 0x0C, AddrType::ADDR_IMMD19}, */
+ {0x10, 0x10, AddrType::ADDR_IMMD19},
+ /* {0x14, 0x14, AddrType::ADDR_IMMD19}, */
+ /* {0x18, 0x18, AddrType::ADDR_IMMD26}, */
+ {0x1C, 0x1C, AddrType::ADDR_IMMD26},
+ {0x20, 0x20, AddrType::ADDR_IMMD26},
+ {0x24, 0x24, AddrType::ADDR_IMMD26},
+ };
+
+ ConstBufferView image = ConstBufferView::FromRange(std::begin(kDataAarch64),
+ std::end(kDataAarch64));
+ std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch64),
+ std::end(kAbs32Aarch64));
+ AddressTranslator translator(GetTrivialTranslator(image.size()));
+ Rel32FinderAArch64 rel32_finder(image, translator);
+
+ std::vector<Result> results = ArmExtractRel32(
+ image, abs32_locations, DisassemblerElfAArch64::Traits::kVAWidth,
+ std::move(rel32_finder));
+
+ EXPECT_EQ(expected_results, results);
}
} // namespace zucchini