Skip to content

Commit c4fc563

Browse files
[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.
1 parent c9f5b5c commit c4fc563

File tree

4 files changed

+124
-21
lines changed

4 files changed

+124
-21
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ enum EdgeKind_aarch32 : Edge::Kind {
4141
/// Absolute 32-bit value relocation
4242
Data_Pointer32,
4343

44-
LastDataRelocation = Data_Pointer32,
44+
/// Create GOT entry and store offset
45+
Data_RequestGOTAndTransformToDelta32,
46+
47+
LastDataRelocation = Data_RequestGOTAndTransformToDelta32,
4548

4649
///
4750
/// 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,
318321
llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
319322
}
320323

324+
/// Populate a Global Offset Table from edges that request it.
325+
class GOTBuilder : public TableManager<GOTBuilder> {
326+
public:
327+
static StringRef getSectionName() { return "$__GOT"; }
328+
329+
bool visitEdge(LinkGraph &G, Block *B, Edge &E);
330+
Symbol &createEntry(LinkGraph &G, Symbol &Target);
331+
332+
private:
333+
Section *GOTSection = nullptr;
334+
};
335+
321336
/// Stubs builder for v7 emits non-position-independent Thumb stubs.
322337
///
323338
/// Right now we only have one default stub kind, but we want to extend this

llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType) {
3535
switch (ELFType) {
3636
case ELF::R_ARM_ABS32:
3737
return aarch32::Data_Pointer32;
38+
case ELF::R_ARM_GOT_PREL:
39+
return aarch32::Data_RequestGOTAndTransformToDelta32;
3840
case ELF::R_ARM_REL32:
3941
return aarch32::Data_Delta32;
4042
case ELF::R_ARM_CALL:
@@ -71,6 +73,8 @@ Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
7173
return ELF::R_ARM_REL32;
7274
case aarch32::Data_Pointer32:
7375
return ELF::R_ARM_ABS32;
76+
case aarch32::Data_RequestGOTAndTransformToDelta32:
77+
return ELF::R_ARM_GOT_PREL;
7478
case aarch32::Arm_Call:
7579
return ELF::R_ARM_CALL;
7680
case aarch32::Arm_Jump24:
@@ -222,6 +226,9 @@ Error buildTables_ELF_aarch32(LinkGraph &G) {
222226

223227
StubsManagerType StubsManager;
224228
visitExistingEdges(G, StubsManager);
229+
aarch32::GOTBuilder GOT;
230+
visitExistingEdges(G, GOT);
231+
225232
return Error::success();
226233
}
227234

llvm/lib/ExecutionEngine/JITLink/aarch32.cpp

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
395395
switch (Kind) {
396396
case Data_Delta32:
397397
case Data_Pointer32:
398+
case Data_RequestGOTAndTransformToDelta32:
398399
return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
399400
default:
400401
return make_error<JITLinkError>(
@@ -464,15 +465,6 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
464465
char *BlockWorkingMem = B.getAlreadyMutableContent().data();
465466
char *FixupPtr = BlockWorkingMem + E.getOffset();
466467

467-
auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) {
468-
assert(isInt<32>(Value) && "Must be in signed 32-bit range");
469-
uint32_t Imm = static_cast<int32_t>(Value);
470-
if (LLVM_LIKELY(Endian == endianness::little))
471-
endian::write32<endianness::little>(FixupPtr, Imm);
472-
else
473-
endian::write32<endianness::big>(FixupPtr, Imm);
474-
};
475-
476468
Edge::Kind Kind = E.getKind();
477469
uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
478470
int64_t Addend = E.getAddend();
@@ -487,16 +479,24 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
487479
int64_t Value = TargetAddress - FixupAddress + Addend;
488480
if (!isInt<32>(Value))
489481
return makeTargetOutOfRangeError(G, B, E);
490-
Write32(Value);
482+
if (LLVM_LIKELY(G.getEndianness() == endianness::little))
483+
endian::write32le(FixupPtr, Value);
484+
else
485+
endian::write32be(FixupPtr, Value);
491486
return Error::success();
492487
}
493488
case Data_Pointer32: {
494489
int64_t Value = TargetAddress + Addend;
495-
if (!isInt<32>(Value))
490+
if (!isUInt<32>(Value))
496491
return makeTargetOutOfRangeError(G, B, E);
497-
Write32(Value);
492+
if (LLVM_LIKELY(G.getEndianness() == endianness::little))
493+
endian::write32le(FixupPtr, Value);
494+
else
495+
endian::write32be(FixupPtr, Value);
498496
return Error::success();
499497
}
498+
case Data_RequestGOTAndTransformToDelta32:
499+
llvm_unreachable("Should be transformed");
500500
default:
501501
return make_error<JITLinkError>(
502502
"In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -678,6 +678,52 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
678678
}
679679
}
680680

681+
const uint8_t GOTEntryInit[] = {
682+
0x00,
683+
0x00,
684+
0x00,
685+
0x00,
686+
};
687+
688+
/// Create a new node in the link-graph for the given pointer value.
689+
template <size_t Size>
690+
static Block &allocPointer(LinkGraph &G, Section &S,
691+
const uint8_t (&Content)[Size]) {
692+
static_assert(Size == 4, "Pointers are 32-bit");
693+
constexpr uint64_t Alignment = 4;
694+
ArrayRef<char> Init(reinterpret_cast<const char *>(Content), Size);
695+
return G.createContentBlock(S, Init, orc::ExecutorAddr(), Alignment, 0);
696+
}
697+
698+
Symbol &GOTBuilder::createEntry(LinkGraph &G, Symbol &Target) {
699+
if (!GOTSection)
700+
GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
701+
Block &B = allocPointer(G, *GOTSection, GOTEntryInit);
702+
constexpr int64_t GOTEntryAddend = 0;
703+
B.addEdge(Data_Pointer32, 0, Target, GOTEntryAddend);
704+
return G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
705+
}
706+
707+
bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) {
708+
Edge::Kind KindToSet = Edge::Invalid;
709+
switch (E.getKind()) {
710+
case aarch32::Data_RequestGOTAndTransformToDelta32: {
711+
KindToSet = aarch32::Data_Delta32;
712+
break;
713+
}
714+
default:
715+
return false;
716+
}
717+
LLVM_DEBUG(dbgs() << " Transforming " << G.getEdgeKindName(E.getKind())
718+
<< " edge at " << B->getFixupAddress(E) << " ("
719+
<< B->getAddress() << " + "
720+
<< formatv("{0:x}", E.getOffset()) << ") into "
721+
<< G.getEdgeKindName(KindToSet) << "\n");
722+
E.setKind(KindToSet);
723+
E.setTarget(getEntryForTarget(G, E.getTarget()));
724+
return true;
725+
}
726+
681727
const uint8_t Thumbv7ABS[] = {
682728
0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit
683729
0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit
@@ -709,6 +755,7 @@ const char *getEdgeKindName(Edge::Kind K) {
709755
switch (K) {
710756
KIND_NAME_CASE(Data_Delta32)
711757
KIND_NAME_CASE(Data_Pointer32)
758+
KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32)
712759
KIND_NAME_CASE(Arm_Call)
713760
KIND_NAME_CASE(Arm_Jump24)
714761
KIND_NAME_CASE(Arm_MovwAbsNC)

llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# RUN: llvm-mc -triple=armv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv7.o %s
2-
# RUN: llvm-objdump -r %t_armv7.o | FileCheck --check-prefix=CHECK-TYPE %s
1+
# RUN: rm -rf %t && mkdir -p %t/armv7 && mkdir -p %t/thumbv7
2+
# RUN: llvm-mc -triple=armv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/armv7/out.o %s
3+
# RUN: llvm-objdump -r %t/armv7/out.o | FileCheck --check-prefix=CHECK-TYPE %s
34
# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
4-
# RUN: -abs target=0x76bbe88f -check %s %t_armv7.o
5+
# RUN: -abs target=0x76bbe88f -check %s %t/armv7/out.o
56

6-
# RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7.o %s
7-
# RUN: llvm-objdump -r %t_thumbv7.o | FileCheck --check-prefix=CHECK-TYPE %s
7+
# RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/thumbv7/out.o %s
8+
# RUN: llvm-objdump -r %t/thumbv7/out.o | FileCheck --check-prefix=CHECK-TYPE %s
89
# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
9-
# RUN: -abs target=0x76bbe88f -check %s %t_thumbv7.o
10+
# RUN: -abs target=0x76bbe88f -check %s %t/thumbv7/out.o
1011

1112
.data
1213
.global target
@@ -28,10 +29,43 @@ rel32:
2829
.word target - .
2930
.size rel32, .-rel32
3031

31-
# Empty main function for jitlink to be happy
32+
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_GOT_PREL target
33+
#
34+
# The GOT entry contains the absolute address of the external:
35+
# jitlink-check: *{4}(got_addr(out.o, target)) = target
36+
#
37+
# The embedded offset value contains the offset to the GOT entry relative to pc.
38+
# The +12 accounts for the ARM branch offset (8) and the .LPC offset (4), which
39+
# is stored as initial addend inline.
40+
# FIXME: We shouldn't need to substract the 64-bit sign-extension manually.
41+
# jitlink-check: *{4}got_prel_offset = got_addr(out.o, target) - (got_prel + 12) - 0xffffffff00000000
42+
.globl got_prel
43+
.type got_prel,%function
44+
.p2align 2
45+
.code 32
46+
got_prel:
47+
ldr r0, .LCPI
48+
.LPC:
49+
ldr r0, [pc, r0]
50+
ldr r0, [r0]
51+
bx lr
52+
# Actual relocation site is on the embedded offset value:
53+
.globl got_prel_offset
54+
got_prel_offset:
55+
.LCPI:
56+
.long target(GOT_PREL)-((.LPC+8)-.LCPI)
57+
.size got_prel_offset, .-got_prel_offset
58+
.size got_prel, .-got_prel
59+
60+
# This test is executable with any 4-byte external target:
61+
# > echo "unsigned target = 42;" | clang -target armv7-linux-gnueabihf -o target.o -c -xc -
62+
# > llvm-jitlink target.o armv7/out.o
63+
#
3264
.globl main
3365
.type main, %function
3466
.p2align 2
3567
main:
36-
bx lr
68+
push {lr}
69+
bl got_prel
70+
pop {pc}
3771
.size main, .-main

0 commit comments

Comments
 (0)