[llvm] [JITLink][AArch64] Implement R_AARCH64_LDR_PREL_LO19 (PR #82172)

Pavel Samolysov via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 18 07:58:49 PST 2024


https://github.com/samolisov created https://github.com/llvm/llvm-project/pull/82172

This relocation is used for the 32-bit aligned 21-bit immediate in LDR Literal instructions.

>From 58ccbd0c159faa35ffd998cbb7405ebf82981678 Mon Sep 17 00:00:00 2001
From: Pavel Samolysov <samolisov at gmail.com>
Date: Sun, 18 Feb 2024 16:49:39 +0300
Subject: [PATCH] [JITLink][AArch64] Implement R_AARCH64_LDR_PREL_LO19

This relocation is used for the 32-bit aligned 21-bit immediate in LDR
Literal instructions.
---
 .../llvm/ExecutionEngine/JITLink/aarch64.h        | 15 +++++++++------
 llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp  | 12 ++++++++++++
 .../JITLink/AArch64/ELF_relocations.s             | 15 +++++++++++++++
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
index 40b9339eb5316d..4d081589ac403c 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
@@ -171,7 +171,7 @@ enum EdgeKind_aarch64 : Edge::Kind {
   ///
   /// Fixup expression:
   ///
-  ///   Fixup <- (Target - Fixup) >> 2 : int19
+  ///   Fixup <- (Target - Fixup + Addend) >> 2 : int19
   ///
   /// Errors:
   ///   - The result of the unshifted part of the fixup expression must be
@@ -377,6 +377,11 @@ inline bool isADR(uint32_t Instr) {
   return (Instr & ADRMask) == 0x10000000;
 }
 
+inline bool isLDRLiteral(uint32_t Instr) {
+  constexpr uint32_t LDRLitMask = 0x3b000000;
+  return (Instr & LDRLitMask) == 0x18000000;
+}
+
 // Returns the amount the address operand of LD/ST (imm12)
 // should be shifted right by.
 //
@@ -494,16 +499,14 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
   }
   case LDRLiteral19: {
     assert((FixupAddress.getValue() & 0x3) == 0 && "LDR is not 32-bit aligned");
-    assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
-    assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
-    int64_t Delta = E.getTarget().getAddress() - FixupAddress;
+    assert(isLDRLiteral(RawInstr) && "RawInstr is not an LDR Literal");
+    int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
     if (Delta & 0x3)
       return make_error<JITLinkError>("LDR literal target is not 32-bit "
                                       "aligned");
-    if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
+    if (!isInt<21>(Delta))
       return makeTargetOutOfRangeError(G, B, E);
-
     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
     uint32_t FixedInstr = RawInstr | EncodedImm;
     *(ulittle32_t *)FixupPtr = FixedInstr;
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
index f17b2c626ac250..6cd2b7e03a58dd 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
@@ -47,6 +47,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
 private:
   enum ELFAArch64RelocationKind : Edge::Kind {
     ELFCall26 = Edge::FirstRelocation,
+    ELFLdrLo19,
     ELFAdrLo21,
     ELFAdrPage21,
     ELFAddAbs12,
@@ -80,6 +81,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
     case ELF::R_AARCH64_CALL26:
     case ELF::R_AARCH64_JUMP26:
       return ELFCall26;
+    case ELF::R_AARCH64_LD_PREL_LO19:
+      return ELFLdrLo19;
     case ELF::R_AARCH64_ADR_PREL_LO21:
       return ELFAdrLo21;
     case ELF::R_AARCH64_ADR_PREL_PG_HI21:
@@ -189,6 +192,15 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
       Kind = aarch64::Branch26PCRel;
       break;
     }
+    case ELFLdrLo19: {
+      uint32_t Instr = *(const ulittle32_t *)FixupContent;
+      if (!aarch64::isLDRLiteral(Instr))
+        return make_error<JITLinkError>(
+            "R_AARCH64_LDR_PREL_LO19 target is not an LDR Literal instruction");
+
+      Kind = aarch64::LDRLiteral19;
+      break;
+    }
     case ELFAdrLo21: {
       uint32_t Instr = *(const ulittle32_t *)FixupContent;
       if (!aarch64::isADR(Instr))
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s
index b260961f741d72..b837ac18afd270 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s
@@ -51,6 +51,21 @@ test_adr_prel_lo21:
 ## to test this bit better
 adr_data = test_adr_prel_lo21 + 0xe46f2
 
+# Check R_AARCH64_LD_PREL_LO19 relocation of a local symbol
+#
+# jitlink-check: decode_operand(test_ldr_prel_lo19 + 12, 1)[19:0] = \
+# jitlink-check:     (ldr_data - test_ldr_prel_lo19_inst + 0x4)[21:2]
+        .globl  test_ldr_prel_lo19, test_ldr_prel_lo19_inst, ldr_data
+        .p2align  2
+test_ldr_prel_lo19:
+        nop
+        nop
+        nop
+test_ldr_prel_lo19_inst:
+        ldr	x0, ldr_data + 0x4
+        .size test_ldr_prel_lo19, .-test_ldr_prel_lo19
+ldr_data = test_ldr_prel_lo19 + 4
+
 # Check R_AARCH64_ADR_PREL_PG_HI21 / R_AARCH64_ADD_ABS_LO12_NC relocation of a local symbol
 #
 # For the ADR_PREL_PG_HI21/ADRP instruction we have the 21-bit delta to the 4k page



More information about the llvm-commits mailing list