@@ -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.
433597inline 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.
739800class PLTTableManager : public TableManager <PLTTableManager> {
740801public:
0 commit comments