[llvm] [JITLink][AArch32] Implement R_ARM_PREL31 and process .ARM.exidx sections (PR #79044)

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 22 11:54:59 PST 2024


https://github.com/weliveindetail created https://github.com/llvm/llvm-project/pull/79044

`R_ARM_PREL31` is a 31-bits relative data relocation where the most-significant bit is preserved. It's used primarily in `.ARM.exidx` sections, which we skipped processing until now, because we didn't support the relocation type. This was implemented in RuntimeDyld with https://reviews.llvm.org/D25069 and I implemented it in a similar way in JITLink in order to reach feature parity.

>From 1eb3193da0a581e562da2c2f52391c86f1b0a875 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 20 Jan 2024 16:00:51 +0100
Subject: [PATCH] [JITLink][AArch32] Implement R_ARM_PREL31 and process
 .ARM.exidx sections

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    |  2 ++
 .../JITLink/ELFLinkGraphBuilder.h             |  5 +++++
 .../ExecutionEngine/JITLink/ELF_aarch32.cpp   | 14 ++++---------
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 21 ++++++++++++++++---
 .../JITLink/AArch32/ELF_relocations_data.s    | 20 ++++++++++++++----
 5 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 081f77a85e182a..24448e35f7bbd3 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -41,6 +41,8 @@ enum EdgeKind_aarch32 : Edge::Kind {
   /// Absolute 32-bit value relocation
   Data_Pointer32,
 
+  Data_PRel31,
+
   /// Create GOT entry and store offset
   Data_RequestGOTAndTransformToDelta32,
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
index 56d1efa4bdef70..e4e0c2555215c2 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
@@ -397,6 +397,11 @@ template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {
                                   orc::ExecutorAddr(Sec.sh_addr),
                                   Sec.sh_addralign, 0);
 
+    if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {
+      // Add live symbol to avoid dead-stripping for .ARM.exidx sections
+      G->addAnonymousSymbol(*B, orc::ExecutorAddrDiff(), orc::ExecutorAddrDiff(), false, true);
+    }
+
     setGraphBlock(SecIndex, B);
   }
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index 15c209e1ebe5bf..dfe6ab14adc279 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -50,6 +50,8 @@ getJITLinkEdgeKind(uint32_t ELFType, const aarch32::ArmConfig &ArmCfg) {
     return aarch32::Arm_MovtAbs;
   case ELF::R_ARM_NONE:
     return aarch32::None;
+  case ELF::R_ARM_PREL31:
+    return aarch32::Data_PRel31;
   case ELF::R_ARM_TARGET1:
     return (ArmCfg.Target1Rel) ? aarch32::Data_Delta32
                                : aarch32::Data_Pointer32;
@@ -79,6 +81,8 @@ Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
     return ELF::R_ARM_REL32;
   case aarch32::Data_Pointer32:
     return ELF::R_ARM_ABS32;
+  case aarch32::Data_PRel31:
+    return ELF::R_ARM_PREL31;
   case aarch32::Data_RequestGOTAndTransformToDelta32:
     return ELF::R_ARM_GOT_PREL;
   case aarch32::Arm_Call:
@@ -140,16 +144,6 @@ class ELFLinkGraphBuilder_aarch32
   using ELFT = ELFType<DataEndianness, false>;
   using Base = ELFLinkGraphBuilder<ELFT>;
 
-  bool excludeSection(const typename ELFT::Shdr &Sect) const override {
-    // TODO: An .ARM.exidx (Exception Index table) entry is 8-bytes in size and
-    // consists of 2 words. It might be sufficient to process only relocations
-    // in the the second word (offset 4). Please find more details in: Exception
-    // Handling ABI for the Arm® Architecture -> Index table entries
-    if (Sect.sh_type == ELF::SHT_ARM_EXIDX)
-      return true;
-    return false;
-  }
-
   Error addRelocations() override {
     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
     using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>;
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 1797a0068cd7cd..57835102ce2b68 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -397,6 +397,8 @@ Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
   case Data_Pointer32:
   case Data_RequestGOTAndTransformToDelta32:
     return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
+  case Data_PRel31:
+    return SignExtend64<31>(support::endian::read32(FixupPtr, Endian));
   default:
     return make_error<JITLinkError>(
         "In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -471,9 +473,8 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
   Symbol &TargetSymbol = E.getTarget();
   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
 
-  // Regular data relocations have size 4, alignment 1 and write the full 32-bit
-  // result to the place; no need for overflow checking. There are three
-  // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
+  // Data relocations have alignment 1, size 4 (except R_ARM_ABS8 and
+  // R_ARM_ABS16) and write the full 32-bit result (except R_ARM_PREL31).
   switch (Kind) {
   case Data_Delta32: {
     int64_t Value = TargetAddress - FixupAddress + Addend;
@@ -495,6 +496,19 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
       endian::write32be(FixupPtr, Value);
     return Error::success();
   }
+  case Data_PRel31: {
+    int64_t Value = TargetAddress - FixupAddress + Addend;
+    if (!isInt<31>(Value))
+      return makeTargetOutOfRangeError(G, B, E);
+    if (LLVM_LIKELY(G.getEndianness() == endianness::little)) {
+      uint32_t MSB = endian::read32le(FixupPtr) & 0x80000000;
+      endian::write32le(FixupPtr, MSB | (Value & ~0x80000000));
+    } else {
+      uint32_t MSB = endian::read32be(FixupPtr) & 0x80000000;
+      endian::write32be(FixupPtr, MSB | (Value & ~0x80000000));
+    }
+    return Error::success();
+  }
   case Data_RequestGOTAndTransformToDelta32:
     llvm_unreachable("Should be transformed");
   default:
@@ -755,6 +769,7 @@ const char *getEdgeKindName(Edge::Kind K) {
   switch (K) {
     KIND_NAME_CASE(Data_Delta32)
     KIND_NAME_CASE(Data_Pointer32)
+    KIND_NAME_CASE(Data_PRel31)
     KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32)
     KIND_NAME_CASE(Arm_Call)
     KIND_NAME_CASE(Arm_Jump24)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
index 7bd59f8a52de6d..544e8c259d2868 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
@@ -64,7 +64,7 @@ got_prel_offset:
 	.size	got_prel_offset, .-got_prel_offset
 	.size	got_prel, .-got_prel
 
-# EH personality routine
+# EH personality routine in .ARM.exidx
 # CHECK-TYPE: {{[0-9a-f]+}} R_ARM_NONE __aeabi_unwind_cpp_pr0
 	.globl __aeabi_unwind_cpp_pr0
 	.type __aeabi_unwind_cpp_pr0,%function
@@ -72,8 +72,19 @@ got_prel_offset:
 __aeabi_unwind_cpp_pr0:
 	bx lr
 
-# Generate reference to EH personality (right now we ignore the resulting
-# R_ARM_PREL31 relocation since it's in .ARM.exidx)
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_PREL31 .text
+#
+# An .ARM.exidx table entry is 8-bytes in size, made up of 2 4-byte entries.
+# First word contains offset to function for this entry:
+# jitlink-check: (*{4}section_addr(out.o, .ARM.exidx))[31:0] = prel31 - section_addr(out.o, .ARM.exidx)
+#
+# Most-significant bit in second word denotes inline entry when set (and
+# relocation to .ARM.extab otherwise). Inline entry with compact model index 0:
+#   0x9b      vsp = r11
+#   0x84 0x80 pop {r11, r14}
+#
+# jitlink-check: *{4}(section_addr(out.o, .ARM.exidx) + 4) = 0x809b8480
+#
 	.globl  prel31
 	.type   prel31,%function
 	.align  2
@@ -85,8 +96,8 @@ prel31:
 	mov     r11, sp
 	pop     {r11, lr}
 	mov     pc, lr
-	.size   prel31,.-prel31
 	.fnend
+	.size   prel31,.-prel31
 
 # This test is executable with any 4-byte external target:
 #  > echo "unsigned target = 42;" | clang -target armv7-linux-gnueabihf -o target.o -c -xc -
@@ -98,5 +109,6 @@ prel31:
 main:
 	push	{lr}
 	bl	got_prel
+	bl	prel31
 	pop	{pc}
 	.size   main, .-main



More information about the llvm-commits mailing list