[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