[llvm] [JITLink][AArch32] Draft fixture class for fixup tests and out-of-range errors in particular (PR #73397)

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 28 14:12:01 PST 2023


https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/73397

>From b6c6d8a47728b7eefeb681979b3b3cbf451db5c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 25 Nov 2023 14:22:16 +0100
Subject: [PATCH 1/2] [JITLink][AArch32] Split out error test for invalid edge
 in applyFixup()

Also rename the fixture class since these tests are not ELF-specific.
---
 .../JITLink/AArch32ErrorTests.cpp             | 44 +++++++++++++------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
index c3bf45e03398c28..ef8f14e0d051267 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
@@ -33,13 +33,14 @@ constexpr uint64_t AlignmentOffset = 0;
 constexpr orc::ExecutorAddrDiff SymbolOffset = 0;
 constexpr orc::ExecutorAddrDiff SymbolSize = 4;
 
-class AArch32Errors_ELF : public testing::Test {
+class AArch32Errors : public testing::Test {
 protected:
-  ArmConfig ArmCfg = getArmConfigForCPUArch(ARMBuildAttrs::v7);
+  const ArmConfig Cfg = getArmConfigForCPUArch(ARMBuildAttrs::v7);
   std::unique_ptr<LinkGraph> G;
   Section *S = nullptr;
 
   const uint8_t Zeros[4]{0x00, 0x00, 0x00, 0x00};
+  uint8_t MutableZeros[4]{0x00, 0x00, 0x00, 0x00};
 
 public:
   static void SetUpTestCase() {}
@@ -62,15 +63,24 @@ class AArch32Errors_ELF : public testing::Test {
     return G->createContentBlock(*S, CharContent, orc::ExecutorAddr(Addr),
                                  Alignment, AlignmentOffset);
   }
+
+  template <size_t Size>
+  Block &createMutableBlock(uint8_t (&Content)[Size], uint64_t Addr,
+                            uint64_t Alignment = 4) {
+    MutableArrayRef<char> CharContent{reinterpret_cast<char *>(&Content),
+                                      sizeof(Content)};
+    return G->createMutableContentBlock(
+        *S, CharContent, orc::ExecutorAddr(Addr), Alignment, AlignmentOffset);
+  }
 };
 
-TEST_F(AArch32Errors_ELF, readAddendDataErrors) {
+TEST_F(AArch32Errors, readAddendDataGeneric) {
   Block &ZerosBlock = createBlock(Zeros, 0x1000);
   constexpr uint64_t ZerosOffset = 0;
 
   // Invalid edge kind is the only error we can raise here right now.
   Edge::Kind Invalid = Edge::GenericEdgeKind::Invalid;
-  EXPECT_THAT_EXPECTED(readAddend(*G, ZerosBlock, ZerosOffset, Invalid, ArmCfg),
+  EXPECT_THAT_EXPECTED(readAddend(*G, ZerosBlock, ZerosOffset, Invalid, Cfg),
                        FailedWithMessage(testing::HasSubstr(
                            "can not read implicit addend for aarch32 edge kind "
                            "INVALID RELOCATION")));
@@ -121,6 +131,23 @@ TEST(AArch32_ELF, readAddendThumbErrors) {
   }
 }
 
+TEST_F(AArch32Errors, applyFixupDataGeneric) {
+  Block &OriginBlock = createMutableBlock(MutableZeros, 0x1000);
+  Block &TargetBlock = createBlock(Zeros, 0x2000);
+
+  constexpr uint64_t OffsetInTarget = 0;
+  Symbol &TargetSymbol = G->addAnonymousSymbol(TargetBlock, OffsetInTarget,
+                                               PointerSize, false, false);
+
+  constexpr uint64_t OffsetInOrigin = 0;
+  Edge::Kind Invalid = Edge::GenericEdgeKind::Invalid;
+  Edge InvalidEdge(Invalid, OffsetInOrigin, TargetSymbol, 0 /*Addend*/);
+  EXPECT_THAT_ERROR(
+      applyFixup(*G, OriginBlock, InvalidEdge, Cfg),
+      FailedWithMessage(testing::HasSubstr(
+          "encountered unfixable aarch32 edge kind INVALID RELOCATION")));
+}
+
 TEST(AArch32_ELF, applyFixupArmErrors) {
 
   constexpr orc::ExecutorAddr B3DummyAddr(0x5000);
@@ -134,13 +161,6 @@ TEST(AArch32_ELF, applyFixupArmErrors) {
 
   Symbol &TargetSymbol =
       G->addAnonymousSymbol(BArm, SymbolOffset, SymbolSize, false, false);
-  Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
-                   0 /*Addend*/);
-
-  EXPECT_THAT_ERROR(
-      applyFixup(*G, BArm, InvalidEdge, ArmCfg),
-      FailedWithMessage(testing::HasSubstr(
-          "encountered unfixable aarch32 edge kind INVALID RELOCATION")));
 
   for (Edge::Kind K = FirstArmRelocation; K < LastArmRelocation; K += 1) {
     Edge E(K, 0, TargetSymbol, 0);
@@ -180,8 +200,6 @@ TEST(AArch32_ELF, applyFixupThumbErrors) {
       Sec, MutableThumbContent, B4DummyAddr, ThumbAlignment, AlignmentOffset);
   Symbol &TargetSymbol =
       G->addAnonymousSymbol(BThumb, SymbolOffset, SymbolSize, false, false);
-  Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
-                   0 /*Addend*/);
 
   for (Edge::Kind K = FirstThumbRelocation; K < LastThumbRelocation; K += 1) {
     Edge E(K, 0, TargetSymbol, 0);

>From f4d92c8a1f92b386a2c0f5724f275a694557f44d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 25 Nov 2023 17:05:46 +0100
Subject: [PATCH 2/2] [JITLink][AArch32] Test out-of-range and interworking
 errors for Thumb Call and Jump24

---
 .../JITLink/AArch32ErrorTests.cpp             | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
index ef8f14e0d051267..614bfb7d54d3fee 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
@@ -72,6 +72,17 @@ class AArch32Errors : public testing::Test {
     return G->createMutableContentBlock(
         *S, CharContent, orc::ExecutorAddr(Addr), Alignment, AlignmentOffset);
   }
+
+  Symbol &createSymbolWithDistance(Block &Origin, uint64_t Dist) {
+    uint64_t TargetAddr = Origin.getAddress().getValue() + Dist;
+    return G->addAnonymousSymbol(createBlock(Zeros, TargetAddr), 0 /*Offset*/,
+                                 PointerSize, false, false);
+  };
+
+  template <endianness Endian> void write(uint8_t *Mem, HalfWords Data) {
+    write16<Endian>(Mem, Data.Hi);
+    write16<Endian>(Mem + 2, Data.Lo);
+  }
 };
 
 TEST_F(AArch32Errors, readAddendDataGeneric) {
@@ -209,3 +220,83 @@ TEST(AArch32_ELF, applyFixupThumbErrors) {
                           testing::EndsWith(aarch32::getEdgeKindName(K)))));
   }
 }
+
+TEST_F(AArch32Errors, applyFixupThumbCall) {
+  // Check range of R_ARM_THM_CALL relocation
+  constexpr uint64_t Call1Offset = 0; //< first out-of-range
+  constexpr uint64_t Call2Offset = 4; //< last in-range
+
+  uint8_t TwoCallsMem[8];
+  Block &Site = createMutableBlock(TwoCallsMem, 0);
+  constexpr HalfWords CallOpcode = FixupInfo<Thumb_Call>::Opcode;
+  write<endianness::little>(TwoCallsMem + Call1Offset, CallOpcode);
+  write<endianness::little>(TwoCallsMem + Call2Offset, CallOpcode);
+
+  // Thumb call with J1J2-encoding has range of 25 bit
+  ArmConfig ArmCfg;
+  ArmCfg.J1J2BranchEncoding = true;
+  Symbol &J1J2Target = createSymbolWithDistance(Site, 0x01ull << 24);
+  {
+    Edge LastInRange(Thumb_Call, Call2Offset, J1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());
+    Edge FirstOutOfRange(Thumb_Call, Call1Offset, J1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),
+                      FailedWithMessage(testing::HasSubstr("out of range")));
+  }
+
+  // Thumb call without J1J2-encoding has range of 22 bit
+  ArmCfg.J1J2BranchEncoding = false;
+  Symbol &NonJ1J2Target = createSymbolWithDistance(Site, 0x01ull << 21);
+  {
+    Edge LastInRange(Thumb_Call, Call2Offset, NonJ1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());
+    Edge FirstOutOfRange(Thumb_Call, Call1Offset, NonJ1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),
+                      FailedWithMessage(testing::HasSubstr("out of range")));
+  }
+}
+
+TEST_F(AArch32Errors, applyFixupThumbJump24) {
+  // Check range of R_ARM_THM_JUMP24 relocation
+  constexpr uint64_t Jump1Offset = 0; //< first out-of-range
+  constexpr uint64_t Jump2Offset = 4; //< last in-range
+
+  uint8_t TwoJumpsMem[8];
+  constexpr HalfWords JumpOpcode = FixupInfo<Thumb_Jump24>::Opcode;
+  write<endianness::little>(TwoJumpsMem + Jump1Offset, JumpOpcode);
+  write<endianness::little>(TwoJumpsMem + Jump2Offset, JumpOpcode);
+  Block &Site = createMutableBlock(TwoJumpsMem, 0);
+
+  // Thumb Jump24 with J1J2-encoding has range of 25 bit
+  ArmCfg.J1J2BranchEncoding = true;
+  Symbol &J1J2Target = createSymbolWithDistance(Site, 0x01ull << 24);
+  J1J2Target.setTargetFlags(TargetFlags_aarch32::ThumbSymbol);
+  {
+    Edge LastInRange(Thumb_Jump24, Jump2Offset, J1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());
+    Edge FirstOutOfRange(Thumb_Jump24, Jump1Offset, J1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),
+                      FailedWithMessage(testing::HasSubstr("out of range")));
+  }
+
+  // Thumb Jump24 without J1J2-encoding has range of 22 bit
+  ArmCfg.J1J2BranchEncoding = false;
+  Symbol &NonJ1J2Target = createSymbolWithDistance(Site, 0x01ull << 21);
+  NonJ1J2Target.setTargetFlags(TargetFlags_aarch32::ThumbSymbol);
+  {
+    Edge LastInRange(Thumb_Jump24, Jump2Offset, NonJ1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());
+    Edge FirstOutOfRange(Thumb_Jump24, Jump1Offset, NonJ1J2Target, 0);
+    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),
+                      FailedWithMessage(testing::HasSubstr("out of range")));
+  }
+
+  // Check that branching to an ARM target with Jump24 fails
+  Symbol &ArmTarget = createSymbolWithDistance(Site, 0x1000);
+  assert((J1J2Target.getTargetFlags() & TargetFlags_aarch32::ThumbSymbol) == 0);
+  Edge Interworking(Thumb_Jump24, Jump2Offset, ArmTarget, 0);
+  EXPECT_THAT_ERROR(applyFixup(*G, Site, Interworking, ArmCfg),
+                    FailedWithMessage(testing::HasSubstr(
+                        "Branch relocation needs interworking "
+                        "stub when bridging to ARM")));
+}



More information about the llvm-commits mailing list