@@ -233,6 +233,21 @@ enum EdgeKind_aarch64 : Edge::Kind {
233
233
// / out-of-range error will be returned.
234
234
PageOffset12,
235
235
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
+
236
251
// / A GOT entry getter/constructor, transformed to Page21 pointing at the GOT
237
252
// / entry for the original target.
238
253
// /
@@ -273,6 +288,23 @@ enum EdgeKind_aarch64 : Edge::Kind {
273
288
// /
274
289
RequestGOTAndTransformToPageOffset12,
275
290
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
+
276
308
// / A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
277
309
// / entry for the original target.
278
310
// /
@@ -429,6 +461,138 @@ inline unsigned getMoveWide16Shift(uint32_t Instr) {
429
461
return 0 ;
430
462
}
431
463
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
+
432
596
// / Apply fixup expression for edge to block content.
433
597
inline Error applyFixup (LinkGraph &G, Block &B, const Edge &E) {
434
598
using namespace support ;
@@ -603,6 +767,26 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
603
767
*(ulittle32_t *)FixupPtr = FixedInstr;
604
768
break ;
605
769
}
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
+ }
606
790
default :
607
791
return make_error<JITLinkError>(
608
792
" In graph " + G.getName () + " , section " + B.getSection ().getName () +
@@ -612,129 +796,6 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
612
796
return Error::success ();
613
797
}
614
798
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
-
738
799
// / Procedure Linkage Table Builder.
739
800
class PLTTableManager : public TableManager <PLTTableManager> {
740
801
public:
0 commit comments