@@ -496,7 +496,7 @@ BinaryContext::handleAddressRef(uint64_t Address, BinaryFunction &BF,
496
496
const MemoryContentsType MemType = analyzeMemoryAt (Address, BF);
497
497
if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE && IsPCRel) {
498
498
const MCSymbol *Symbol =
499
- getOrCreateJumpTable (BF, Address, JumpTable::JTT_PIC );
499
+ getOrCreateJumpTable (BF, Address, JumpTable::JTT_X86_64_PIC4 );
500
500
501
501
return std::make_pair (Symbol, 0 );
502
502
}
@@ -540,10 +540,10 @@ MemoryContentsType BinaryContext::analyzeMemoryAt(uint64_t Address,
540
540
541
541
// Start with checking for PIC jump table. We expect non-PIC jump tables
542
542
// to have high 32 bits set to 0.
543
- if (analyzeJumpTable (Address, JumpTable::JTT_PIC , BF))
543
+ if (analyzeJumpTable (Address, JumpTable::JTT_X86_64_PIC4 , BF))
544
544
return MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE;
545
545
546
- if (analyzeJumpTable (Address, JumpTable::JTT_NORMAL , BF))
546
+ if (analyzeJumpTable (Address, JumpTable::JTT_X86_64_ABS , BF))
547
547
return MemoryContentsType::POSSIBLE_JUMP_TABLE;
548
548
549
549
return MemoryContentsType::UNKNOWN;
@@ -553,8 +553,7 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
553
553
const JumpTable::JumpTableType Type,
554
554
const BinaryFunction &BF,
555
555
const uint64_t NextJTAddress,
556
- JumpTable::AddressesType *EntriesAsAddress,
557
- bool *HasEntryInFragment) const {
556
+ JumpTable *JT) const {
558
557
// Target address of __builtin_unreachable.
559
558
const uint64_t UnreachableAddress = BF.getAddress () + BF.getSize ();
560
559
@@ -571,11 +570,11 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
571
570
size_t TrimmedSize = 0 ;
572
571
573
572
auto addEntryAddress = [&](uint64_t EntryAddress, bool Unreachable = false ) {
574
- if (!EntriesAsAddress )
573
+ if (!JT )
575
574
return ;
576
- EntriesAsAddress-> emplace_back (EntryAddress);
575
+ JT-> EntriesAsAddress . emplace_back (EntryAddress);
577
576
if (!Unreachable)
578
- TrimmedSize = EntriesAsAddress-> size ();
577
+ TrimmedSize = JT-> EntriesAsAddress . size ();
579
578
};
580
579
581
580
ErrorOr<const BinarySection &> Section = getSectionForAddress (Address);
@@ -594,37 +593,48 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
594
593
if (NextJTAddress)
595
594
UpperBound = std::min (NextJTAddress, UpperBound);
596
595
597
- LLVM_DEBUG ({
598
- using JTT = JumpTable::JumpTableType;
599
- dbgs () << formatv (" BOLT-DEBUG: analyzeJumpTable @{0:x} in {1}, JTT={2}\n " ,
600
- Address, BF.getPrintName (),
601
- Type == JTT::JTT_PIC ? " PIC" : " Normal" );
602
- });
596
+ LLVM_DEBUG (
597
+ dbgs () << formatv (" BOLT-DEBUG: analyzeJumpTable @{0:x} in {1}, JTT={2}\n " ,
598
+ Address, BF, JumpTable::getTypeStr (Type)));
603
599
const uint64_t EntrySize = getJumpTableEntrySize (Type);
604
600
for (uint64_t EntryAddress = Address; EntryAddress <= UpperBound - EntrySize;
605
601
EntryAddress += EntrySize) {
606
602
LLVM_DEBUG (dbgs () << " * Checking 0x" << Twine::utohexstr (EntryAddress)
607
603
<< " -> " );
608
604
// Check if there's a proper relocation against the jump table entry.
609
605
if (HasRelocations) {
610
- if (Type == JumpTable::JTT_PIC &&
606
+ if (Type == JumpTable::JTT_X86_64_PIC4 &&
611
607
!DataPCRelocations.count (EntryAddress)) {
612
608
LLVM_DEBUG (
613
609
dbgs () << " FAIL: JTT_PIC table, no relocation for this address\n " );
614
610
break ;
615
611
}
616
- if (Type == JumpTable::JTT_NORMAL && !getRelocationAt (EntryAddress)) {
612
+ if (Type == JumpTable::JTT_X86_64_ABS && !getRelocationAt (EntryAddress)) {
617
613
LLVM_DEBUG (
618
614
dbgs ()
619
615
<< " FAIL: JTT_NORMAL table, no relocation for this address\n " );
620
616
break ;
621
617
}
622
618
}
623
619
624
- const uint64_t Value =
625
- (Type == JumpTable::JTT_PIC)
626
- ? Address + *getSignedValueAtAddress (EntryAddress, EntrySize)
627
- : *getPointerAtAddress (EntryAddress);
620
+ uint64_t Value = 0 ;
621
+ switch (Type) {
622
+ case JumpTable::JTT_X86_64_PIC4:
623
+ Value = Address + *getSignedValueAtAddress (EntryAddress, EntrySize);
624
+ break ;
625
+ case JumpTable::JTT_X86_64_ABS:
626
+ Value = *getPointerAtAddress (EntryAddress);
627
+ break ;
628
+ case JumpTable::JTT_AARCH64_REL1:
629
+ case JumpTable::JTT_AARCH64_REL2:
630
+ case JumpTable::JTT_AARCH64_REL4:
631
+ unsigned ShiftAmt = Type == JumpTable::JTT_AARCH64_REL4 ? 0 : 2 ;
632
+ assert (JT &&
633
+ " jump table must be non-null for AArch64 in analyzeJumpTable" );
634
+ Value = JT->BaseAddress +
635
+ (*getUnsignedValueAtAddress (EntryAddress, EntrySize) << ShiftAmt);
636
+ break ;
637
+ }
628
638
629
639
// __builtin_unreachable() case.
630
640
if (Value == UnreachableAddress) {
@@ -645,24 +655,19 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
645
655
646
656
// Function or one of its fragments.
647
657
const BinaryFunction *TargetBF = getBinaryFunctionContainingAddress (Value);
648
- const bool DoesBelongToFunction =
649
- BF.containsAddress (Value) ||
650
- (TargetBF && areRelatedFragments (TargetBF, &BF));
651
- if (!DoesBelongToFunction) {
658
+ if (!TargetBF || !areRelatedFragments (TargetBF, &BF)) {
652
659
LLVM_DEBUG ({
653
- if (!BF.containsAddress (Value)) {
654
- dbgs () << " FAIL: function doesn't contain this address\n " ;
655
- if (TargetBF) {
656
- dbgs () << " ! function containing this address: "
657
- << TargetBF->getPrintName () << ' \n ' ;
658
- if (TargetBF->isFragment ()) {
659
- dbgs () << " ! is a fragment" ;
660
- for (BinaryFunction *Parent : TargetBF->ParentFragments )
661
- dbgs () << " , parent: " << Parent->getPrintName ();
662
- dbgs () << ' \n ' ;
663
- }
664
- }
665
- }
660
+ dbgs () << " FAIL: function doesn't contain this address\n " ;
661
+ if (!TargetBF)
662
+ break ;
663
+ dbgs () << " ! function containing this address: " << *TargetBF << ' \n ' ;
664
+ if (!TargetBF->isFragment ())
665
+ break ;
666
+ dbgs () << " ! is a fragment with parents: " ;
667
+ ListSeparator LS;
668
+ for (BinaryFunction *Parent : TargetBF->ParentFragments )
669
+ dbgs () << LS << *Parent;
670
+ dbgs () << ' \n ' ;
666
671
});
667
672
break ;
668
673
}
@@ -677,17 +682,17 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
677
682
++NumRealEntries;
678
683
LLVM_DEBUG (dbgs () << formatv (" OK: {0:x} real entry\n " , Value));
679
684
680
- if (TargetBF != &BF && HasEntryInFragment )
681
- *HasEntryInFragment = true ;
685
+ if (TargetBF != &BF && JT )
686
+ JT-> IsSplit = true ;
682
687
addEntryAddress (Value);
683
688
}
684
689
685
690
// Trim direct/normal jump table to exclude trailing unreachable entries that
686
691
// can collide with a function address.
687
- if (Type == JumpTable::JTT_NORMAL && EntriesAsAddress &&
688
- TrimmedSize != EntriesAsAddress-> size () &&
692
+ if (Type == JumpTable::JTT_X86_64_ABS && JT &&
693
+ TrimmedSize != JT-> EntriesAsAddress . size () &&
689
694
getBinaryFunctionAtAddress (UnreachableAddress))
690
- EntriesAsAddress-> resize (TrimmedSize);
695
+ JT-> EntriesAsAddress . resize (TrimmedSize);
691
696
692
697
// It's a jump table if the number of real entries is more than 1, or there's
693
698
// one real entry and one or more special targets. If there are only multiple
@@ -702,20 +707,20 @@ void BinaryContext::populateJumpTables() {
702
707
++JTI) {
703
708
JumpTable *JT = JTI->second ;
704
709
705
- bool NonSimpleParent = false ;
706
- for (BinaryFunction *BF : JT->Parents )
707
- NonSimpleParent |= !BF->isSimple ();
708
- if (NonSimpleParent)
710
+ auto isSimple = std::bind (&BinaryFunction::isSimple, std::placeholders::_1);
711
+ if (!llvm::all_of (JT->Parents , isSimple))
709
712
continue ;
710
713
711
714
uint64_t NextJTAddress = 0 ;
712
715
auto NextJTI = std::next (JTI);
713
- if (NextJTI != JTE)
716
+ if (isAArch64 ()) {
717
+ NextJTAddress = JT->getAddress () + JT->getSize ();
718
+ JT->Entries .clear ();
719
+ } else if (NextJTI != JTE)
714
720
NextJTAddress = NextJTI->second ->getAddress ();
715
721
716
- const bool Success =
717
- analyzeJumpTable (JT->getAddress (), JT->Type , *(JT->Parents [0 ]),
718
- NextJTAddress, &JT->EntriesAsAddress , &JT->IsSplit );
722
+ const bool Success = analyzeJumpTable (
723
+ JT->getAddress (), JT->Type , *JT->Parents .front (), NextJTAddress, JT);
719
724
if (!Success) {
720
725
LLVM_DEBUG ({
721
726
dbgs () << " failed to analyze " ;
@@ -743,7 +748,7 @@ void BinaryContext::populateJumpTables() {
743
748
744
749
// In strict mode, erase PC-relative relocation record. Later we check that
745
750
// all such records are erased and thus have been accounted for.
746
- if (opts::StrictMode && JT->Type == JumpTable::JTT_PIC ) {
751
+ if (opts::StrictMode && JT->Type == JumpTable::JTT_X86_64_PIC4 ) {
747
752
for (uint64_t Address = JT->getAddress ();
748
753
Address < JT->getAddress () + JT->getSize ();
749
754
Address += JT->EntrySize ) {
@@ -839,33 +844,26 @@ BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,
839
844
assert (JT->Type == Type && " jump table types have to match" );
840
845
assert (Address == JT->getAddress () && " unexpected non-empty jump table" );
841
846
842
- // Prevent associating a jump table to a specific fragment twice.
843
- if (!llvm::is_contained (JT->Parents , &Function)) {
844
- assert (llvm::all_of (JT->Parents ,
845
- [&](const BinaryFunction *BF) {
846
- return areRelatedFragments (&Function, BF);
847
- }) &&
848
- " cannot re-use jump table of a different function" );
849
- // Duplicate the entry for the parent function for easy access
850
- JT->Parents .push_back (&Function);
851
- if (opts::Verbosity > 2 ) {
852
- this ->outs () << " BOLT-INFO: Multiple fragments access same jump table: "
853
- << JT->Parents [0 ]->getPrintName () << " ; "
854
- << Function.getPrintName () << " \n " ;
855
- JT->print (this ->outs ());
856
- }
857
- Function.JumpTables .emplace (Address, JT);
858
- for (BinaryFunction *Parent : JT->Parents )
859
- Parent->setHasIndirectTargetToSplitFragment (true );
860
- }
847
+ if (llvm::is_contained (JT->Parents , &Function))
848
+ return JT->getFirstLabel ();
861
849
862
- bool IsJumpTableParent = false ;
863
- (void )IsJumpTableParent;
864
- for (BinaryFunction *Frag : JT->Parents )
865
- if (Frag == &Function)
866
- IsJumpTableParent = true ;
867
- assert (IsJumpTableParent &&
850
+ // Prevent associating a jump table to a specific fragment twice.
851
+ auto isSibling = std::bind (&BinaryContext::areRelatedFragments, this ,
852
+ &Function, std::placeholders::_1);
853
+ assert (llvm::all_of (JT->Parents , isSibling) &&
868
854
" cannot re-use jump table of a different function" );
855
+ if (opts::Verbosity > 2 ) {
856
+ this ->outs () << " BOLT-INFO: Multiple fragments access same jump table: "
857
+ << JT->Parents [0 ]->getPrintName () << " ; "
858
+ << Function.getPrintName () << " \n " ;
859
+ JT->print (this ->outs ());
860
+ }
861
+ if (JT->Parents .size () == 1 )
862
+ JT->Parents .front ()->setHasIndirectTargetToSplitFragment (true );
863
+ Function.setHasIndirectTargetToSplitFragment (true );
864
+ // Duplicate the entry for the parent function for easy access
865
+ JT->Parents .push_back (&Function);
866
+ Function.JumpTables .emplace (Address, JT);
869
867
return JT->getFirstLabel ();
870
868
}
871
869
0 commit comments