Skip to content

Commit dc971be

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 dc971be

File tree

5 files changed

+217
-123
lines changed

5 files changed

+217
-123
lines changed

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

+6
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,12 @@ class Section {
758758
return make_range(Symbols.begin(), Symbols.end());
759759
}
760760

761+
/// Returns address of the section
762+
uint64_t getAddress() const {
763+
assert(Symbols.size() && "Section has no symbols");
764+
return (*Symbols.begin())->getAddress().getValue();
765+
}
766+
761767
/// Return the number of symbols in this section.
762768
SymbolSet::size_type symbols_size() const { return Symbols.size(); }
763769

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

+184-123
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
///
@@ -429,6 +461,138 @@ inline unsigned getMoveWide16Shift(uint32_t Instr) {
429461
return 0;
430462
}
431463

464+
/// aarch64 pointer size.
465+
constexpr uint64_t PointerSize = 8;
466+
467+
/// AArch64 null pointer content.
468+
extern const char NullPointerContent[PointerSize];
469+
470+
/// AArch64 pointer jump stub content.
471+
///
472+
/// Contains the instruction sequence for an indirect jump via an in-memory
473+
/// pointer:
474+
/// ADRP x16, ptr@page21
475+
/// LDR x16, [x16, ptr@pageoff12]
476+
/// BR x16
477+
extern const char PointerJumpStubContent[12];
478+
479+
/// Creates a new pointer block in the given section and returns an
480+
/// Anonymous symbol pointing to it.
481+
///
482+
/// If InitialTarget is given then an Pointer64 relocation will be added to the
483+
/// block pointing at InitialTarget.
484+
///
485+
/// The pointer block will have the following default values:
486+
/// alignment: 64-bit
487+
/// alignment-offset: 0
488+
/// address: highest allowable (~7U)
489+
inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
490+
Symbol *InitialTarget = nullptr,
491+
uint64_t InitialAddend = 0) {
492+
auto &B = G.createContentBlock(PointerSection, NullPointerContent,
493+
orc::ExecutorAddr(~uint64_t(7)), 8, 0);
494+
if (InitialTarget)
495+
B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
496+
return G.addAnonymousSymbol(B, 0, 8, false, false);
497+
}
498+
499+
/// Create a jump stub block that jumps via the pointer at the given symbol.
500+
///
501+
/// The stub block will have the following default values:
502+
/// alignment: 32-bit
503+
/// alignment-offset: 0
504+
/// address: highest allowable: (~11U)
505+
inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
506+
Symbol &PointerSymbol) {
507+
auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
508+
orc::ExecutorAddr(~uint64_t(11)), 4, 0);
509+
B.addEdge(Page21, 0, PointerSymbol, 0);
510+
B.addEdge(PageOffset12, 4, PointerSymbol, 0);
511+
return B;
512+
}
513+
514+
/// Create a jump stub that jumps via the pointer at the given symbol and
515+
/// an anonymous symbol pointing to it. Return the anonymous symbol.
516+
///
517+
/// The stub block will be created by createPointerJumpStubBlock.
518+
inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
519+
Section &StubSection,
520+
Symbol &PointerSymbol) {
521+
return G.addAnonymousSymbol(
522+
createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0,
523+
sizeof(PointerJumpStubContent), true, false);
524+
}
525+
526+
/// Global Offset Table Builder.
527+
class GOTTableManager : public TableManager<GOTTableManager> {
528+
public:
529+
static StringRef getSectionName() { return "$__GOT"; }
530+
531+
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
532+
Edge::Kind KindToSet = Edge::Invalid;
533+
const char *BlockWorkingMem = B->getContent().data();
534+
const char *FixupPtr = BlockWorkingMem + E.getOffset();
535+
536+
switch (E.getKind()) {
537+
case aarch64::RequestGOTAndTransformToPage21:
538+
case aarch64::RequestTLVPAndTransformToPage21: {
539+
KindToSet = aarch64::Page21;
540+
break;
541+
}
542+
case aarch64::RequestGOTAndTransformToPageOffset12:
543+
case aarch64::RequestTLVPAndTransformToPageOffset12: {
544+
KindToSet = aarch64::PageOffset12;
545+
uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
546+
(void)RawInstr;
547+
assert(E.getAddend() == 0 &&
548+
"GOTPageOffset12/TLVPageOffset12 with non-zero addend");
549+
assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
550+
"RawInstr isn't a 64-bit LDR immediate");
551+
break;
552+
}
553+
case aarch64::RequestGOTAndTransformToPageOffset15: {
554+
KindToSet = aarch64::GotPageOffset15;
555+
uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
556+
(void)RawInstr;
557+
assert(E.getAddend() == 0 && "GOTPageOffset15 with non-zero addend");
558+
assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
559+
"RawInstr isn't a 64-bit LDR immediate");
560+
break;
561+
}
562+
case aarch64::RequestGOTAndTransformToDelta32: {
563+
KindToSet = aarch64::Delta32;
564+
break;
565+
}
566+
default:
567+
return false;
568+
}
569+
assert(KindToSet != Edge::Invalid &&
570+
"Fell through switch, but no new kind to set");
571+
DEBUG_WITH_TYPE("jitlink", {
572+
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
573+
<< B->getFixupAddress(E) << " (" << B->getAddress() << " + "
574+
<< formatv("{0:x}", E.getOffset()) << ")\n";
575+
});
576+
E.setKind(KindToSet);
577+
E.setTarget(getEntryForTarget(G, E.getTarget()));
578+
return true;
579+
}
580+
581+
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
582+
return createAnonymousPointer(G, getGOTSection(G), &Target);
583+
}
584+
585+
private:
586+
Section &getGOTSection(LinkGraph &G) {
587+
if (!GOTSection)
588+
GOTSection = &G.createSection(getSectionName(),
589+
orc::MemProt::Read | orc::MemProt::Exec);
590+
return *GOTSection;
591+
}
592+
593+
Section *GOTSection = nullptr;
594+
};
595+
432596
/// Apply fixup expression for edge to block content.
433597
inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
434598
using namespace support;
@@ -603,6 +767,26 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
603767
*(ulittle32_t *)FixupPtr = FixedInstr;
604768
break;
605769
}
770+
case GotPageOffset15: {
771+
Section *GOTSection =
772+
G.findSectionByName(aarch64::GOTTableManager::getSectionName());
773+
assert(GOTSection && "GOT section not found");
774+
uint64_t TargetOffset =
775+
(E.getTarget().getAddress() + E.getAddend()).getValue() -
776+
(GOTSection->getAddress() & ~static_cast<uint64_t>(4096 - 1));
777+
if (TargetOffset > 0x7fff)
778+
return make_error<JITLinkError>("PAGEOFF15 target is out of range");
779+
780+
uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
781+
const unsigned ImmShift = 3;
782+
if (TargetOffset & ((1 << ImmShift) - 1))
783+
return make_error<JITLinkError>("PAGEOFF15 target is not aligned");
784+
785+
uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
786+
uint32_t FixedInstr = RawInstr | EncodedImm;
787+
*(ulittle32_t *)FixupPtr = FixedInstr;
788+
break;
789+
}
606790
default:
607791
return make_error<JITLinkError>(
608792
"In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -612,129 +796,6 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
612796
return Error::success();
613797
}
614798

615-
/// aarch64 pointer size.
616-
constexpr uint64_t PointerSize = 8;
617-
618-
/// AArch64 null pointer content.
619-
extern const char NullPointerContent[PointerSize];
620-
621-
/// AArch64 pointer jump stub content.
622-
///
623-
/// Contains the instruction sequence for an indirect jump via an in-memory
624-
/// pointer:
625-
/// ADRP x16, ptr@page21
626-
/// LDR x16, [x16, ptr@pageoff12]
627-
/// BR x16
628-
extern const char PointerJumpStubContent[12];
629-
630-
/// Creates a new pointer block in the given section and returns an
631-
/// Anonymous symbol pointing to it.
632-
///
633-
/// If InitialTarget is given then an Pointer64 relocation will be added to the
634-
/// block pointing at InitialTarget.
635-
///
636-
/// The pointer block will have the following default values:
637-
/// alignment: 64-bit
638-
/// alignment-offset: 0
639-
/// address: highest allowable (~7U)
640-
inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
641-
Symbol *InitialTarget = nullptr,
642-
uint64_t InitialAddend = 0) {
643-
auto &B = G.createContentBlock(PointerSection, NullPointerContent,
644-
orc::ExecutorAddr(~uint64_t(7)), 8, 0);
645-
if (InitialTarget)
646-
B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
647-
return G.addAnonymousSymbol(B, 0, 8, false, false);
648-
}
649-
650-
/// Create a jump stub block that jumps via the pointer at the given symbol.
651-
///
652-
/// The stub block will have the following default values:
653-
/// alignment: 32-bit
654-
/// alignment-offset: 0
655-
/// address: highest allowable: (~11U)
656-
inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
657-
Symbol &PointerSymbol) {
658-
auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
659-
orc::ExecutorAddr(~uint64_t(11)), 4, 0);
660-
B.addEdge(Page21, 0, PointerSymbol, 0);
661-
B.addEdge(PageOffset12, 4, PointerSymbol, 0);
662-
return B;
663-
}
664-
665-
/// Create a jump stub that jumps via the pointer at the given symbol and
666-
/// an anonymous symbol pointing to it. Return the anonymous symbol.
667-
///
668-
/// The stub block will be created by createPointerJumpStubBlock.
669-
inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
670-
Section &StubSection,
671-
Symbol &PointerSymbol) {
672-
return G.addAnonymousSymbol(
673-
createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0,
674-
sizeof(PointerJumpStubContent), true, false);
675-
}
676-
677-
/// Global Offset Table Builder.
678-
class GOTTableManager : public TableManager<GOTTableManager> {
679-
public:
680-
static StringRef getSectionName() { return "$__GOT"; }
681-
682-
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
683-
Edge::Kind KindToSet = Edge::Invalid;
684-
const char *BlockWorkingMem = B->getContent().data();
685-
const char *FixupPtr = BlockWorkingMem + E.getOffset();
686-
687-
switch (E.getKind()) {
688-
case aarch64::RequestGOTAndTransformToPage21:
689-
case aarch64::RequestTLVPAndTransformToPage21: {
690-
KindToSet = aarch64::Page21;
691-
break;
692-
}
693-
case aarch64::RequestGOTAndTransformToPageOffset12:
694-
case aarch64::RequestTLVPAndTransformToPageOffset12: {
695-
KindToSet = aarch64::PageOffset12;
696-
uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
697-
(void)RawInstr;
698-
assert(E.getAddend() == 0 &&
699-
"GOTPageOffset12/TLVPageOffset12 with non-zero addend");
700-
assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
701-
"RawInstr isn't a 64-bit LDR immediate");
702-
break;
703-
}
704-
case aarch64::RequestGOTAndTransformToDelta32: {
705-
KindToSet = aarch64::Delta32;
706-
break;
707-
}
708-
default:
709-
return false;
710-
}
711-
assert(KindToSet != Edge::Invalid &&
712-
"Fell through switch, but no new kind to set");
713-
DEBUG_WITH_TYPE("jitlink", {
714-
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
715-
<< B->getFixupAddress(E) << " (" << B->getAddress() << " + "
716-
<< formatv("{0:x}", E.getOffset()) << ")\n";
717-
});
718-
E.setKind(KindToSet);
719-
E.setTarget(getEntryForTarget(G, E.getTarget()));
720-
return true;
721-
}
722-
723-
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
724-
return createAnonymousPointer(G, getGOTSection(G), &Target);
725-
}
726-
727-
private:
728-
Section &getGOTSection(LinkGraph &G) {
729-
if (!GOTSection)
730-
GOTSection = &G.createSection(getSectionName(),
731-
orc::MemProt::Read | orc::MemProt::Exec);
732-
return *GOTSection;
733-
}
734-
735-
Section *GOTSection = nullptr;
736-
};
737-
738799
/// Procedure Linkage Table Builder.
739800
class PLTTableManager : public TableManager<PLTTableManager> {
740801
public:

llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
7070
ELFPrel64,
7171
ELFAdrGOTPage21,
7272
ELFLd64GOTLo12,
73+
ELFLd64GOTPAGELo15,
7374
ELFTLSDescAdrPage21,
7475
ELFTLSDescAddLo12,
7576
ELFTLSDescLd64Lo12,
@@ -125,6 +126,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
125126
return ELFAdrGOTPage21;
126127
case ELF::R_AARCH64_LD64_GOT_LO12_NC:
127128
return ELFLd64GOTLo12;
129+
case ELF::R_AARCH64_LD64_GOTPAGE_LO15:
130+
return ELFLd64GOTPAGELo15;
128131
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
129132
return ELFTLSDescAdrPage21;
130133
case ELF::R_AARCH64_TLSDESC_ADD_LO12:
@@ -362,6 +365,10 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
362365
Kind = aarch64::RequestGOTAndTransformToPageOffset12;
363366
break;
364367
}
368+
case ELFLd64GOTPAGELo15: {
369+
Kind = aarch64::RequestGOTAndTransformToPageOffset15;
370+
break;
371+
}
365372
case ELFTLSDescAdrPage21: {
366373
Kind = aarch64::RequestTLSDescEntryAndTransformToPage21;
367374
break;
@@ -427,6 +434,8 @@ class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
427434
return "ELFAdrGOTPage21";
428435
case ELFLd64GOTLo12:
429436
return "ELFLd64GOTLo12";
437+
case ELFLd64GOTPAGELo15:
438+
return "ELFLd64GOTPAGELo15";
430439
case ELFTLSDescAdrPage21:
431440
return "ELFTLSDescAdrPage21";
432441
case ELFTLSDescAddLo12:

0 commit comments

Comments
 (0)