[llvm] c4fc563 - [JITLink][AArch32] Add GOT builder and implement R_ARM_GOT_PREL relocations for ELF (#78753)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 22 03:00:28 PST 2024


Author: Stefan Gränitz
Date: 2024-01-22T12:00:24+01:00
New Revision: c4fc563b8d41c28f3e4cbcd4ef943c26d234b5ae

URL: https://github.com/llvm/llvm-project/commit/c4fc563b8d41c28f3e4cbcd4ef943c26d234b5ae
DIFF: https://github.com/llvm/llvm-project/commit/c4fc563b8d41c28f3e4cbcd4ef943c26d234b5ae.diff

LOG: [JITLink][AArch32] Add GOT builder and implement R_ARM_GOT_PREL relocations for ELF (#78753)

LLJIT needs this relocation for running deinitializers. Implementation and
test are adapted from test arm-fpic-got.s in LLD.

Added: 
    

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
    llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
    llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 7765208b5e3dfe..0968a093279bfb 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -41,7 +41,10 @@ enum EdgeKind_aarch32 : Edge::Kind {
   /// Absolute 32-bit value relocation
   Data_Pointer32,
 
-  LastDataRelocation = Data_Pointer32,
+  /// Create GOT entry and store offset
+  Data_RequestGOTAndTransformToDelta32,
+
+  LastDataRelocation = Data_RequestGOTAndTransformToDelta32,
 
   ///
   /// Relocations of class Arm (covers fixed-width 4-byte instruction subset)
@@ -318,6 +321,18 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
 }
 
+/// Populate a Global Offset Table from edges that request it.
+class GOTBuilder : public TableManager<GOTBuilder> {
+public:
+  static StringRef getSectionName() { return "$__GOT"; }
+
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E);
+  Symbol &createEntry(LinkGraph &G, Symbol &Target);
+
+private:
+  Section *GOTSection = nullptr;
+};
+
 /// Stubs builder for v7 emits non-position-independent Thumb stubs.
 ///
 /// Right now we only have one default stub kind, but we want to extend this

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index b862a7ba2acc92..2553cd70a57691 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -35,6 +35,8 @@ Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType) {
   switch (ELFType) {
   case ELF::R_ARM_ABS32:
     return aarch32::Data_Pointer32;
+  case ELF::R_ARM_GOT_PREL:
+    return aarch32::Data_RequestGOTAndTransformToDelta32;
   case ELF::R_ARM_REL32:
     return aarch32::Data_Delta32;
   case ELF::R_ARM_CALL:
@@ -71,6 +73,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_RequestGOTAndTransformToDelta32:
+    return ELF::R_ARM_GOT_PREL;
   case aarch32::Arm_Call:
     return ELF::R_ARM_CALL;
   case aarch32::Arm_Jump24:
@@ -222,6 +226,9 @@ Error buildTables_ELF_aarch32(LinkGraph &G) {
 
   StubsManagerType StubsManager;
   visitExistingEdges(G, StubsManager);
+  aarch32::GOTBuilder GOT;
+  visitExistingEdges(G, GOT);
+
   return Error::success();
 }
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 8153c97deff628..111527a39e06ec 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -395,6 +395,7 @@ Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
   switch (Kind) {
   case Data_Delta32:
   case Data_Pointer32:
+  case Data_RequestGOTAndTransformToDelta32:
     return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
   default:
     return make_error<JITLinkError>(
@@ -464,15 +465,6 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
   char *FixupPtr = BlockWorkingMem + E.getOffset();
 
-  auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) {
-    assert(isInt<32>(Value) && "Must be in signed 32-bit range");
-    uint32_t Imm = static_cast<int32_t>(Value);
-    if (LLVM_LIKELY(Endian == endianness::little))
-      endian::write32<endianness::little>(FixupPtr, Imm);
-    else
-      endian::write32<endianness::big>(FixupPtr, Imm);
-  };
-
   Edge::Kind Kind = E.getKind();
   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
   int64_t Addend = E.getAddend();
@@ -487,16 +479,24 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
     int64_t Value = TargetAddress - FixupAddress + Addend;
     if (!isInt<32>(Value))
       return makeTargetOutOfRangeError(G, B, E);
-    Write32(Value);
+    if (LLVM_LIKELY(G.getEndianness() == endianness::little))
+      endian::write32le(FixupPtr, Value);
+    else
+      endian::write32be(FixupPtr, Value);
     return Error::success();
   }
   case Data_Pointer32: {
     int64_t Value = TargetAddress + Addend;
-    if (!isInt<32>(Value))
+    if (!isUInt<32>(Value))
       return makeTargetOutOfRangeError(G, B, E);
-    Write32(Value);
+    if (LLVM_LIKELY(G.getEndianness() == endianness::little))
+      endian::write32le(FixupPtr, Value);
+    else
+      endian::write32be(FixupPtr, Value);
     return Error::success();
   }
+  case Data_RequestGOTAndTransformToDelta32:
+    llvm_unreachable("Should be transformed");
   default:
     return make_error<JITLinkError>(
         "In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -678,6 +678,52 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
   }
 }
 
+const uint8_t GOTEntryInit[] = {
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+};
+
+/// Create a new node in the link-graph for the given pointer value.
+template <size_t Size>
+static Block &allocPointer(LinkGraph &G, Section &S,
+                           const uint8_t (&Content)[Size]) {
+  static_assert(Size == 4, "Pointers are 32-bit");
+  constexpr uint64_t Alignment = 4;
+  ArrayRef<char> Init(reinterpret_cast<const char *>(Content), Size);
+  return G.createContentBlock(S, Init, orc::ExecutorAddr(), Alignment, 0);
+}
+
+Symbol &GOTBuilder::createEntry(LinkGraph &G, Symbol &Target) {
+  if (!GOTSection)
+    GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
+  Block &B = allocPointer(G, *GOTSection, GOTEntryInit);
+  constexpr int64_t GOTEntryAddend = 0;
+  B.addEdge(Data_Pointer32, 0, Target, GOTEntryAddend);
+  return G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
+}
+
+bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) {
+  Edge::Kind KindToSet = Edge::Invalid;
+  switch (E.getKind()) {
+  case aarch32::Data_RequestGOTAndTransformToDelta32: {
+    KindToSet = aarch32::Data_Delta32;
+    break;
+  }
+  default:
+    return false;
+  }
+  LLVM_DEBUG(dbgs() << "  Transforming " << G.getEdgeKindName(E.getKind())
+                    << " edge at " << B->getFixupAddress(E) << " ("
+                    << B->getAddress() << " + "
+                    << formatv("{0:x}", E.getOffset()) << ") into "
+                    << G.getEdgeKindName(KindToSet) << "\n");
+  E.setKind(KindToSet);
+  E.setTarget(getEntryForTarget(G, E.getTarget()));
+  return true;
+}
+
 const uint8_t Thumbv7ABS[] = {
     0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000    ; lower 16-bit
     0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000    ; upper 16-bit
@@ -709,6 +755,7 @@ const char *getEdgeKindName(Edge::Kind K) {
   switch (K) {
     KIND_NAME_CASE(Data_Delta32)
     KIND_NAME_CASE(Data_Pointer32)
+    KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32)
     KIND_NAME_CASE(Arm_Call)
     KIND_NAME_CASE(Arm_Jump24)
     KIND_NAME_CASE(Arm_MovwAbsNC)

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
index 379d35fe4902cb..f91a4733c40eee 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
@@ -1,12 +1,13 @@
-# RUN: llvm-mc -triple=armv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv7.o %s
-# RUN: llvm-objdump -r %t_armv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: rm -rf %t && mkdir -p %t/armv7 && mkdir -p %t/thumbv7
+# RUN: llvm-mc -triple=armv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/armv7/out.o %s
+# RUN: llvm-objdump -r %t/armv7/out.o | FileCheck --check-prefix=CHECK-TYPE %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
-# RUN:              -abs target=0x76bbe88f -check %s %t_armv7.o
+# RUN:              -abs target=0x76bbe88f -check %s %t/armv7/out.o
 
-# RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7.o %s
-# RUN: llvm-objdump -r %t_thumbv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/thumbv7/out.o %s
+# RUN: llvm-objdump -r %t/thumbv7/out.o | FileCheck --check-prefix=CHECK-TYPE %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
-# RUN:              -abs target=0x76bbe88f -check %s %t_thumbv7.o
+# RUN:              -abs target=0x76bbe88f -check %s %t/thumbv7/out.o
 
 	.data
 	.global target
@@ -28,10 +29,43 @@ rel32:
 	.word target - .
 	.size rel32, .-rel32
 
-# Empty main function for jitlink to be happy
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_GOT_PREL target
+#
+# The GOT entry contains the absolute address of the external:
+# jitlink-check: *{4}(got_addr(out.o, target)) = target
+#
+# The embedded offset value contains the offset to the GOT entry relative to pc.
+# The +12 accounts for the ARM branch offset (8) and the .LPC offset (4), which
+# is stored as initial addend inline.
+# FIXME: We shouldn't need to substract the 64-bit sign-extension manually.
+# jitlink-check: *{4}got_prel_offset = got_addr(out.o, target) - (got_prel + 12) - 0xffffffff00000000
+	.globl	got_prel
+	.type	got_prel,%function
+	.p2align	2
+	.code	32
+got_prel:
+	ldr	r0, .LCPI
+.LPC:
+	ldr	r0, [pc, r0]
+	ldr	r0, [r0]
+	bx	lr
+# Actual relocation site is on the embedded offset value:
+	.globl	got_prel_offset
+got_prel_offset:
+.LCPI:
+	.long	target(GOT_PREL)-((.LPC+8)-.LCPI)
+	.size	got_prel_offset, .-got_prel_offset
+	.size	got_prel, .-got_prel
+
+# This test is executable with any 4-byte external target:
+#  > echo "unsigned target = 42;" | clang -target armv7-linux-gnueabihf -o target.o -c -xc -
+#  > llvm-jitlink target.o armv7/out.o
+#
 	.globl  main
 	.type main, %function
 	.p2align  2
 main:
-	bx lr
+	push	{lr}
+	bl	got_prel
+	pop	{pc}
 	.size   main, .-main


        


More information about the llvm-commits mailing list