Skip to content

Commit fdde8ef

Browse files
committed
[𝘀𝗽𝗿] changes to main this commit is based on
Created using spr 1.3.4 [skip ci]
1 parent 9925359 commit fdde8ef

13 files changed

+151
-97
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,18 @@ class BinaryContext {
435435

436436
/// Return size of an entry for the given jump table \p Type.
437437
uint64_t getJumpTableEntrySize(JumpTable::JumpTableType Type) const {
438-
return Type == JumpTable::JTT_PIC ? 4 : AsmInfo->getCodePointerSize();
438+
switch (Type) {
439+
case JumpTable::JTT_X86_64_PIC4:
440+
return 4;
441+
case JumpTable::JTT_X86_64_ABS:
442+
return AsmInfo->getCodePointerSize();
443+
case JumpTable::JTT_AARCH64_REL1:
444+
return 1;
445+
case JumpTable::JTT_AARCH64_REL2:
446+
return 2;
447+
case JumpTable::JTT_AARCH64_REL4:
448+
return 4;
449+
}
439450
}
440451

441452
/// Return JumpTable containing a given \p Address.
@@ -573,14 +584,13 @@ class BinaryContext {
573584
/// If \p NextJTAddress is different from zero, it is used as an upper
574585
/// bound for jump table memory layout.
575586
///
576-
/// Optionally, populate \p Address from jump table entries. The entries
577-
/// could be partially populated if the jump table detection fails.
587+
/// If \p JT is set, populate it with jump table entries. The entries could be
588+
/// partially populated if the jump table detection fails.
578589
bool analyzeJumpTable(const uint64_t Address,
579590
const JumpTable::JumpTableType Type,
580591
const BinaryFunction &BF,
581592
const uint64_t NextJTAddress = 0,
582-
JumpTable::AddressesType *EntriesAsAddress = nullptr,
583-
bool *HasEntryInFragment = nullptr) const;
593+
JumpTable *JT = nullptr) const;
584594

585595
/// After jump table locations are established, this function will populate
586596
/// their EntriesAsAddress based on memory contents.

bolt/include/bolt/Core/JumpTable.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,34 @@ class JumpTable : public BinaryData {
4747

4848
public:
4949
enum JumpTableType : char {
50-
JTT_NORMAL,
51-
JTT_PIC,
50+
JTT_X86_64_FIRST = 0,
51+
JTT_X86_64_ABS = JTT_X86_64_FIRST,
52+
JTT_X86_64_PIC4,
53+
JTT_X86_64_LAST = JTT_X86_64_PIC4,
54+
JTT_AARCH64_FIRST,
55+
JTT_AARCH64_REL1 = JTT_AARCH64_FIRST,
56+
JTT_AARCH64_REL2,
57+
JTT_AARCH64_REL4,
58+
JTT_AARCH64_LAST = JTT_AARCH64_REL4
5259
};
5360

61+
static StringRef getTypeStr(JumpTableType Type) {
62+
switch (Type) {
63+
case JTT_X86_64_ABS:
64+
return "X86_64_ABS";
65+
case JTT_X86_64_PIC4:
66+
return "X86_64_PIC4";
67+
case JTT_AARCH64_REL1:
68+
return "AARCH64_REL1";
69+
case JTT_AARCH64_REL2:
70+
return "AARCH64_REL2";
71+
case JTT_AARCH64_REL4:
72+
return "AARCH64_REL4";
73+
}
74+
}
75+
76+
const StringRef getTypeStr() { return getTypeStr(Type); }
77+
5478
/// Branch statistics for jump table entries.
5579
struct JumpInfo {
5680
uint64_t Mispreds{0};

bolt/include/bolt/Rewrite/MetadataManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class MetadataManager {
3131
/// Run initializers after sections are discovered.
3232
void runSectionInitializers();
3333

34+
/// Execute metadata initializers when functions are discovered but not yet
35+
/// disassembled.
36+
void runInitializersPreDisasm();
37+
3438
/// Execute initialization of rewriters while functions are disassembled, but
3539
/// CFG is not yet built.
3640
void runInitializersPreCFG();

bolt/include/bolt/Rewrite/MetadataRewriter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ class MetadataRewriter {
4949
/// but before functions are discovered.
5050
virtual Error sectionInitializer() { return Error::success(); }
5151

52+
/// Run initialization after the functions are identified but not yet
53+
/// disassembled.
54+
virtual Error preDisasmInitializer() { return Error::success(); }
55+
5256
/// Interface for modifying/annotating functions in the binary based on the
5357
/// contents of the section. Functions are in pre-cfg state.
5458
virtual Error preCFGInitializer() { return Error::success(); }

bolt/include/bolt/Rewrite/RewriteInstance.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ class RewriteInstance {
181181
/// Process metadata in sections before functions are discovered.
182182
void processSectionMetadata();
183183

184+
/// Process metadata in special sections before functions are disassembled.
185+
void processMetadataPreDisasm();
186+
184187
/// Process metadata in special sections before CFG is built for functions.
185188
void processMetadataPreCFG();
186189

bolt/lib/Core/BinaryContext.cpp

Lines changed: 61 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ BinaryContext::handleAddressRef(uint64_t Address, BinaryFunction &BF,
496496
const MemoryContentsType MemType = analyzeMemoryAt(Address, BF);
497497
if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE && IsPCRel) {
498498
const MCSymbol *Symbol =
499-
getOrCreateJumpTable(BF, Address, JumpTable::JTT_PIC);
499+
getOrCreateJumpTable(BF, Address, JumpTable::JTT_X86_64_PIC4);
500500

501501
return std::make_pair(Symbol, 0);
502502
}
@@ -540,10 +540,10 @@ MemoryContentsType BinaryContext::analyzeMemoryAt(uint64_t Address,
540540

541541
// Start with checking for PIC jump table. We expect non-PIC jump tables
542542
// 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))
544544
return MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE;
545545

546-
if (analyzeJumpTable(Address, JumpTable::JTT_NORMAL, BF))
546+
if (analyzeJumpTable(Address, JumpTable::JTT_X86_64_ABS, BF))
547547
return MemoryContentsType::POSSIBLE_JUMP_TABLE;
548548

549549
return MemoryContentsType::UNKNOWN;
@@ -553,8 +553,7 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
553553
const JumpTable::JumpTableType Type,
554554
const BinaryFunction &BF,
555555
const uint64_t NextJTAddress,
556-
JumpTable::AddressesType *EntriesAsAddress,
557-
bool *HasEntryInFragment) const {
556+
JumpTable *JT) const {
558557
// Target address of __builtin_unreachable.
559558
const uint64_t UnreachableAddress = BF.getAddress() + BF.getSize();
560559

@@ -571,11 +570,11 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
571570
size_t TrimmedSize = 0;
572571

573572
auto addEntryAddress = [&](uint64_t EntryAddress, bool Unreachable = false) {
574-
if (!EntriesAsAddress)
573+
if (!JT)
575574
return;
576-
EntriesAsAddress->emplace_back(EntryAddress);
575+
JT->EntriesAsAddress.emplace_back(EntryAddress);
577576
if (!Unreachable)
578-
TrimmedSize = EntriesAsAddress->size();
577+
TrimmedSize = JT->EntriesAsAddress.size();
579578
};
580579

581580
ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);
@@ -594,37 +593,39 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
594593
if (NextJTAddress)
595594
UpperBound = std::min(NextJTAddress, UpperBound);
596595

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)));
603599
const uint64_t EntrySize = getJumpTableEntrySize(Type);
604600
for (uint64_t EntryAddress = Address; EntryAddress <= UpperBound - EntrySize;
605601
EntryAddress += EntrySize) {
606602
LLVM_DEBUG(dbgs() << " * Checking 0x" << Twine::utohexstr(EntryAddress)
607603
<< " -> ");
608604
// Check if there's a proper relocation against the jump table entry.
609605
if (HasRelocations) {
610-
if (Type == JumpTable::JTT_PIC &&
606+
if (Type == JumpTable::JTT_X86_64_PIC4 &&
611607
!DataPCRelocations.count(EntryAddress)) {
612608
LLVM_DEBUG(
613609
dbgs() << "FAIL: JTT_PIC table, no relocation for this address\n");
614610
break;
615611
}
616-
if (Type == JumpTable::JTT_NORMAL && !getRelocationAt(EntryAddress)) {
612+
if (Type == JumpTable::JTT_X86_64_ABS && !getRelocationAt(EntryAddress)) {
617613
LLVM_DEBUG(
618614
dbgs()
619615
<< "FAIL: JTT_NORMAL table, no relocation for this address\n");
620616
break;
621617
}
622618
}
623619

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+
}
628629

629630
// __builtin_unreachable() case.
630631
if (Value == UnreachableAddress) {
@@ -645,24 +646,19 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
645646

646647
// Function or one of its fragments.
647648
const BinaryFunction *TargetBF = getBinaryFunctionContainingAddress(Value);
648-
const bool DoesBelongToFunction =
649-
BF.containsAddress(Value) ||
650-
(TargetBF && areRelatedFragments(TargetBF, &BF));
651-
if (!DoesBelongToFunction) {
649+
if (!TargetBF || !areRelatedFragments(TargetBF, &BF)) {
652650
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-
}
651+
dbgs() << "FAIL: function doesn't contain this address\n";
652+
if (!TargetBF)
653+
break;
654+
dbgs() << " ! function containing this address: " << *TargetBF << '\n';
655+
if (!TargetBF->isFragment())
656+
break;
657+
dbgs() << " ! is a fragment with parents: ";
658+
ListSeparator LS;
659+
for (BinaryFunction *Parent : TargetBF->ParentFragments)
660+
dbgs() << LS << *Parent;
661+
dbgs() << '\n';
666662
});
667663
break;
668664
}
@@ -677,17 +673,17 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
677673
++NumRealEntries;
678674
LLVM_DEBUG(dbgs() << formatv("OK: {0:x} real entry\n", Value));
679675

680-
if (TargetBF != &BF && HasEntryInFragment)
681-
*HasEntryInFragment = true;
676+
if (TargetBF != &BF && JT)
677+
JT->IsSplit = true;
682678
addEntryAddress(Value);
683679
}
684680

685681
// Trim direct/normal jump table to exclude trailing unreachable entries that
686682
// can collide with a function address.
687-
if (Type == JumpTable::JTT_NORMAL && EntriesAsAddress &&
688-
TrimmedSize != EntriesAsAddress->size() &&
683+
if (Type == JumpTable::JTT_X86_64_ABS && JT &&
684+
TrimmedSize != JT->EntriesAsAddress.size() &&
689685
getBinaryFunctionAtAddress(UnreachableAddress))
690-
EntriesAsAddress->resize(TrimmedSize);
686+
JT->EntriesAsAddress.resize(TrimmedSize);
691687

692688
// It's a jump table if the number of real entries is more than 1, or there's
693689
// one real entry and one or more special targets. If there are only multiple
@@ -702,20 +698,17 @@ void BinaryContext::populateJumpTables() {
702698
++JTI) {
703699
JumpTable *JT = JTI->second;
704700

705-
bool NonSimpleParent = false;
706-
for (BinaryFunction *BF : JT->Parents)
707-
NonSimpleParent |= !BF->isSimple();
708-
if (NonSimpleParent)
701+
auto isSimple = std::bind(&BinaryFunction::isSimple, std::placeholders::_1);
702+
if (!llvm::all_of(JT->Parents, isSimple))
709703
continue;
710704

711705
uint64_t NextJTAddress = 0;
712706
auto NextJTI = std::next(JTI);
713707
if (NextJTI != JTE)
714708
NextJTAddress = NextJTI->second->getAddress();
715709

716-
const bool Success =
717-
analyzeJumpTable(JT->getAddress(), JT->Type, *(JT->Parents[0]),
718-
NextJTAddress, &JT->EntriesAsAddress, &JT->IsSplit);
710+
const bool Success = analyzeJumpTable(
711+
JT->getAddress(), JT->Type, *JT->Parents.front(), NextJTAddress, JT);
719712
if (!Success) {
720713
LLVM_DEBUG({
721714
dbgs() << "failed to analyze ";
@@ -743,7 +736,7 @@ void BinaryContext::populateJumpTables() {
743736

744737
// In strict mode, erase PC-relative relocation record. Later we check that
745738
// all such records are erased and thus have been accounted for.
746-
if (opts::StrictMode && JT->Type == JumpTable::JTT_PIC) {
739+
if (opts::StrictMode && JT->Type == JumpTable::JTT_X86_64_PIC4) {
747740
for (uint64_t Address = JT->getAddress();
748741
Address < JT->getAddress() + JT->getSize();
749742
Address += JT->EntrySize) {
@@ -839,33 +832,26 @@ BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,
839832
assert(JT->Type == Type && "jump table types have to match");
840833
assert(Address == JT->getAddress() && "unexpected non-empty jump table");
841834

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-
}
835+
if (llvm::is_contained(JT->Parents, &Function))
836+
return JT->getFirstLabel();
861837

862-
bool IsJumpTableParent = false;
863-
(void)IsJumpTableParent;
864-
for (BinaryFunction *Frag : JT->Parents)
865-
if (Frag == &Function)
866-
IsJumpTableParent = true;
867-
assert(IsJumpTableParent &&
838+
// Prevent associating a jump table to a specific fragment twice.
839+
auto isSibling = std::bind(&BinaryContext::areRelatedFragments, this,
840+
&Function, std::placeholders::_1);
841+
assert(llvm::all_of(JT->Parents, isSibling) &&
868842
"cannot re-use jump table of a different function");
843+
if (opts::Verbosity > 2) {
844+
this->outs() << "BOLT-INFO: Multiple fragments access same jump table: "
845+
<< JT->Parents[0]->getPrintName() << "; "
846+
<< Function.getPrintName() << "\n";
847+
JT->print(this->outs());
848+
}
849+
if (JT->Parents.size() == 1)
850+
JT->Parents.front()->setHasIndirectTargetToSplitFragment(true);
851+
Function.setHasIndirectTargetToSplitFragment(true);
852+
// Duplicate the entry for the parent function for easy access
853+
JT->Parents.push_back(&Function);
854+
Function.JumpTables.emplace(Address, JT);
869855
return JT->getFirstLabel();
870856
}
871857

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
850850
}
851851
LastLabel = LI->second;
852852
}
853-
if (JT.Type == JumpTable::JTT_NORMAL) {
853+
if (JT.Type == JumpTable::JTT_X86_64_ABS) {
854854
Streamer.emitSymbolValue(Entry, JT.OutputEntrySize);
855855
} else { // JTT_PIC
856856
const MCSymbolRefExpr *JTExpr =

0 commit comments

Comments
 (0)