Skip to content

Commit 00a67e0

Browse files
committed
[JITLink][AArch64] Add LD64_GOTPAGE_LO15 rel support
This relocation is used in order to address GOT entries using 15 bit offset in ldr instruction. The offset is calculated relative to GOT section page address.
1 parent 0954205 commit 00a67e0

File tree

5 files changed

+165
-4
lines changed

5 files changed

+165
-4
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,21 @@ enum EdgeKind_aarch64 : Edge::Kind {
233233
/// out-of-range error will be returned.
234234
PageOffset12,
235235

236+
/// The 15-bit offset of the GOT entry from the GOT table.
237+
///
238+
/// Used for load/store instructions addressing a GOT entry.
239+
///
240+
/// Fixup expression:
241+
///
242+
/// Fixup <- ((Target + Addend - Page(GOT))) & 0x7fff) >> 3 : uint12
243+
///
244+
/// Errors:
245+
/// - The result of the unshifted part of the fixup expression must be
246+
/// aligned otherwise an alignment error will be returned.
247+
/// - The result of the fixup expression must fit into a uint12 otherwise an
248+
/// out-of-range error will be returned.
249+
GotPageOffset15,
250+
236251
/// A GOT entry getter/constructor, transformed to Page21 pointing at the GOT
237252
/// entry for the original target.
238253
///
@@ -273,6 +288,23 @@ enum EdgeKind_aarch64 : Edge::Kind {
273288
///
274289
RequestGOTAndTransformToPageOffset12,
275290

291+
/// A GOT entry getter/constructor, transformed to Pageoffset15 pointing at
292+
/// the GOT entry for the original target.
293+
///
294+
/// Indicates that this edge should be transformed into a GotPageOffset15
295+
/// targeting the GOT entry for the edge's current target, maintaining the
296+
/// same addend. A GOT entry for the target should be created if one does not
297+
/// already exist.
298+
///
299+
/// Fixup expression:
300+
/// NONE
301+
///
302+
/// Errors:
303+
/// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
304+
/// phase will result in an assert/unreachable during the fixup phase.
305+
///
306+
RequestGOTAndTransformToPageOffset15,
307+
276308
/// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
277309
/// entry for the original target.
278310
///
@@ -430,7 +462,8 @@ inline unsigned getMoveWide16Shift(uint32_t Instr) {
430462
}
431463

432464
/// Apply fixup expression for edge to block content.
433-
inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
465+
inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
466+
const Symbol *GOTSymbol) {
434467
using namespace support;
435468

436469
char *BlockWorkingMem = B.getAlreadyMutableContent().data();
@@ -603,6 +636,24 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
603636
*(ulittle32_t *)FixupPtr = FixedInstr;
604637
break;
605638
}
639+
case GotPageOffset15: {
640+
assert(GOTSymbol && "No GOT section symbol");
641+
uint64_t TargetOffset =
642+
(E.getTarget().getAddress() + E.getAddend()).getValue() -
643+
(GOTSymbol->getAddress().getValue() & ~static_cast<uint64_t>(4096 - 1));
644+
if (TargetOffset > 0x7fff)
645+
return make_error<JITLinkError>("PAGEOFF15 target is out of range");
646+
647+
uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
648+
const unsigned ImmShift = 3;
649+
if (TargetOffset & ((1 << ImmShift) - 1))
650+
return make_error<JITLinkError>("PAGEOFF15 target is not aligned");
651+
652+
uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
653+
uint32_t FixedInstr = RawInstr | EncodedImm;
654+
*(ulittle32_t *)FixupPtr = FixedInstr;
655+
break;
656+
}
606657
default:
607658
return make_error<JITLinkError>(
608659
"In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -701,6 +752,15 @@ class GOTTableManager : public TableManager<GOTTableManager> {
701752
"RawInstr isn't a 64-bit LDR immediate");
702753
break;
703754
}
755+
case aarch64::RequestGOTAndTransformToPageOffset15: {
756+
KindToSet = aarch64::GotPageOffset15;
757+
uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
758+
(void)RawInstr;
759+
assert(E.getAddend() == 0 && "GOTPageOffset15 with non-zero addend");
760+
assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
761+
"RawInstr isn't a 64-bit LDR immediate");
762+
break;
763+
}
704764
case aarch64::RequestGOTAndTransformToDelta32: {
705765
KindToSet = aarch64::Delta32;
706766
break;

llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,92 @@ using namespace llvm::jitlink;
2929

3030
namespace {
3131

32+
constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
33+
3234
class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
3335
friend class JITLinker<ELFJITLinker_aarch64>;
3436

3537
public:
3638
ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
3739
std::unique_ptr<LinkGraph> G,
3840
PassConfiguration PassConfig)
39-
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
41+
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
42+
if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))
43+
getPassConfig().PostAllocationPasses.push_back(
44+
[this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
45+
}
4046

4147
private:
48+
Symbol *GOTSymbol = nullptr;
49+
4250
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
43-
return aarch64::applyFixup(G, B, E);
51+
return aarch64::applyFixup(G, B, E, GOTSymbol);
52+
}
53+
54+
Error getOrCreateGOTSymbol(LinkGraph &G) {
55+
auto DefineExternalGOTSymbolIfPresent =
56+
createDefineExternalSectionStartAndEndSymbolsPass(
57+
[&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
58+
if (Sym.getName() == ELFGOTSymbolName)
59+
if (auto *GOTSection = G.findSectionByName(
60+
aarch64::GOTTableManager::getSectionName())) {
61+
GOTSymbol = &Sym;
62+
return {*GOTSection, true};
63+
}
64+
return {};
65+
});
66+
67+
// Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
68+
// external.
69+
if (auto Err = DefineExternalGOTSymbolIfPresent(G))
70+
return Err;
71+
72+
// If we succeeded then we're done.
73+
if (GOTSymbol)
74+
return Error::success();
75+
76+
// Otherwise look for a GOT section: If it already has a start symbol we'll
77+
// record it, otherwise we'll create our own.
78+
// If there's a GOT section but we didn't find an external GOT symbol...
79+
if (auto *GOTSection =
80+
G.findSectionByName(aarch64::GOTTableManager::getSectionName())) {
81+
82+
// Check for an existing defined symbol.
83+
for (auto *Sym : GOTSection->symbols())
84+
if (Sym->getName() == ELFGOTSymbolName) {
85+
GOTSymbol = Sym;
86+
return Error::success();
87+
}
88+
89+
// If there's no defined symbol then create one.
90+
SectionRange SR(*GOTSection);
91+
if (SR.empty())
92+
GOTSymbol =
93+
&G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
94+
Linkage::Strong, Scope::Local, true);
95+
else
96+
GOTSymbol =
97+
&G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
98+
Linkage::Strong, Scope::Local, false, true);
99+
}
100+
101+
// If we still haven't found a GOT symbol then double check the externals.
102+
// We may have a GOT-relative reference but no GOT section, in which case
103+
// we just need to point the GOT symbol at some address in this graph.
104+
if (!GOTSymbol) {
105+
for (auto *Sym : G.external_symbols()) {
106+
if (Sym->getName() == ELFGOTSymbolName) {
107+
auto Blocks = G.blocks();
108+
if (!Blocks.empty()) {
109+
G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
110+
GOTSymbol = Sym;
111+
break;
112+
}
113+
}
114+
}
115+
}
116+
117+
return Error::success();
44118
}
45119
};
46120

@@ -70,6 +144,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
70144
ELFPrel64,
71145
ELFAdrGOTPage21,
72146
ELFLd64GOTLo12,
147+
ELFLd64GOTPAGELo15,
73148
ELFTLSDescAdrPage21,
74149
ELFTLSDescAddLo12,
75150
ELFTLSDescLd64Lo12,
@@ -125,6 +200,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
125200
return ELFAdrGOTPage21;
126201
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
127202
return ELFLd64GOTLo12;
203+
case ELF::R_AARCH64_LD64_GOTPAGE_LO15:
204+
return ELFLd64GOTPAGELo15;
128205
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
129206
return ELFTLSDescAdrPage21;
130207
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
@@ -362,6 +439,10 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
362439
Kind = aarch64::RequestGOTAndTransformToPageOffset12;
363440
break;
364441
}
442+
case ELFLd64GOTPAGELo15: {
443+
Kind = aarch64::RequestGOTAndTransformToPageOffset15;
444+
break;
445+
}
365446
case ELFTLSDescAdrPage21: {
366447
Kind = aarch64::RequestTLSDescEntryAndTransformToPage21;
367448
break;
@@ -427,6 +508,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
427508
return "ELFAdrGOTPage21";
428509
case ELFLd64GOTLo12:
429510
return "ELFLd64GOTLo12";
511+
case ELFLd64GOTPAGELo15:
512+
return "ELFLd64GOTPAGELo15";
430513
case ELFTLSDescAdrPage21:
431514
return "ELFTLSDescAdrPage21";
432515
case ELFTLSDescAddLo12:

llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
552552

553553
private:
554554
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
555-
return aarch64::applyFixup(G, B, E);
555+
return aarch64::applyFixup(G, B, E, nullptr);
556556
}
557557

558558
uint64_t NullValue = 0;

llvm/lib/ExecutionEngine/JITLink/aarch64.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@ const char *getEdgeKindName(Edge::Kind R) {
5757
return "Page21";
5858
case PageOffset12:
5959
return "PageOffset12";
60+
case GotPageOffset15:
61+
return "GotPageOffset15";
6062
case RequestGOTAndTransformToPage21:
6163
return "RequestGOTAndTransformToPage21";
6264
case RequestGOTAndTransformToPageOffset12:
6365
return "RequestGOTAndTransformToPageOffset12";
66+
case RequestGOTAndTransformToPageOffset15:
67+
return "RequestGOTAndTransformToPageOffset15";
6468
case RequestGOTAndTransformToDelta32:
6569
return "RequestGOTAndTransformToDelta32";
6670
case RequestTLVPAndTransformToPage21:

llvm/test/ExecutionEngine/JITLink/AArch64/ELF_relocations.s

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,20 @@ test_ld64_gotlo12_external:
264264
ldr x0, [x0, :got_lo12:external_data]
265265
.size test_ld64_gotlo12_external, .-test_ld64_gotlo12_external
266266

267+
# Check R_AARCH64_LD64_GOTPAGE_LO15 handling with a reference to an external
268+
# symbol. Validate the reference to the GOT entry.
269+
# For the LDR :gotpage_lo15: instruction we have the 15-bit offset of the GOT
270+
# entry from the page containing the GOT.
271+
# jitlink-check: decode_operand(test_ld64_gotpagelo15_external, 2) = \
272+
# jitlink-check: (got_addr(elf_reloc.o, external_data) - \
273+
# jitlink-check: (section_addr(elf_reloc.o, $__GOT) & 0xfffffffffffff000)) \
274+
# jitlink-check: [15:3]
275+
.globl test_ld64_gotpagelo15_external
276+
.p2align 2
277+
test_ld64_gotpagelo15_external:
278+
ldr x0, [x0, :gotpage_lo15:external_data]
279+
.size test_ld64_gotpagelo15_external, .-test_ld64_gotpagelo15_external
280+
267281
# Check R_AARCH64_TSTBR14 for tbz
268282
#
269283
# jitlink-check: decode_operand(test_tstbr14_tbz, 2) = \

0 commit comments

Comments
 (0)