[BOLT] Change symbol handling for secondary function entries
Summary: Some functions could be called at an address inside their function body. Typically, these functions are written in assembly as C/C++ does not have a multi-entry function concept. The addresses inside a function body that could be referenced from outside are called secondary entry points. In BOLT we support processing functions with secondary/multiple entry points. We used to mark basic blocks representing those entry points with a special flag. There was only one problem - each basic block has exactly one MCSymbol associated with it, and for the most efficient processing we prefer that symbol to be local/temporary. However, in certain scenarios, e.g. when running in non-relocation mode, we need the entry symbol to be global/non-temporary. We could create global symbols for secondary points ahead of time when the entry point is marked in the symbol table. But not all such entries are properly marked. This means that potentially we could discover an entry point only after disassembling the code that references it, and it could happen after a local label was already created at the same location together with all its references. Replacing the local symbol and updating the references turned out to be an error-prone process. This diff takes a different approach. All basic blocks are created with permanently local symbols. Whenever there's a need to add a secondary entry point, we create an extra global symbol or use an existing one at that location. Containing BinaryFunction maps a local symbol of a basic block to the global symbol representing a secondary entry point. This way we can tell if the basic block is a secondary entry point, and we emit both symbols for all secondary entry points. Since secondary entry points are quite rare, the overhead of this approach is minimal. Note that the same location could be referenced via local symbol from inside a function and via global entry point symbol from outside. This is true for both primary and secondary entry points. (cherry picked from FBD21150193)
This commit is contained in:
parent
ac1af09e82
commit
5296b6d12a
@ -37,6 +37,10 @@ bool BinaryBasicBlock::hasCFG() const {
|
||||
return getParent()->hasCFG();
|
||||
}
|
||||
|
||||
bool BinaryBasicBlock::isEntryPoint() const {
|
||||
return getParent()->isEntryPoint(*this);
|
||||
}
|
||||
|
||||
bool BinaryBasicBlock::hasInstructions() const {
|
||||
return getParent()->hasInstructions();
|
||||
}
|
||||
|
@ -125,10 +125,6 @@ private:
|
||||
/// CFI state at the entry to this basic block.
|
||||
int32_t CFIState{-1};
|
||||
|
||||
/// True if this basic block is (potentially) an external entry point into
|
||||
/// the function.
|
||||
bool IsEntryPoint{false};
|
||||
|
||||
/// In cases where the parent function has been split, IsCold == true means
|
||||
/// this BB will be allocated outside its parent function.
|
||||
bool IsCold{false};
|
||||
@ -698,13 +694,9 @@ public:
|
||||
/// Apply a given \p Ratio to the profile information of this basic block.
|
||||
void adjustExecutionCount(double Ratio);
|
||||
|
||||
bool isEntryPoint() const {
|
||||
return IsEntryPoint;
|
||||
}
|
||||
|
||||
void setEntryPoint(bool Value = true) {
|
||||
IsEntryPoint = Value;
|
||||
}
|
||||
/// Return true if the basic block is an entry point into the function
|
||||
/// (either primary or secondary).
|
||||
bool isEntryPoint() const;
|
||||
|
||||
bool isValid() const {
|
||||
return IsValid;
|
||||
|
@ -1016,7 +1016,8 @@ void BinaryContext::processInterproceduralReferences() {
|
||||
}
|
||||
|
||||
if (ContainingFunction->getAddress() != Addr) {
|
||||
ContainingFunction->addEntryPoint(Addr);
|
||||
ContainingFunction->
|
||||
addEntryPointAtOffset(Addr - ContainingFunction->getAddress());
|
||||
if (!HasRelocations) {
|
||||
if (opts::Verbosity >= 1) {
|
||||
errs() << "BOLT-WARNING: Function " << *ContainingFunction
|
||||
@ -1851,7 +1852,7 @@ BinaryFunction *BinaryContext::getFunctionForSymbol(const MCSymbol *Symbol,
|
||||
|
||||
auto *BF = BFI->second;
|
||||
if (EntryDesc)
|
||||
*EntryDesc = BF->getEntryForSymbol(Symbol);
|
||||
*EntryDesc = BF->getEntryIDForSymbol(Symbol);
|
||||
|
||||
return BF;
|
||||
}
|
||||
|
@ -390,6 +390,9 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, bool EmitColdPart,
|
||||
BB->getAlignmentMaxBytes());
|
||||
}
|
||||
Streamer.EmitLabel(BB->getLabel());
|
||||
if (auto *EntrySymbol = BF.getSecondaryEntryPointSymbol(*BB)) {
|
||||
Streamer.EmitLabel(EntrySymbol);
|
||||
}
|
||||
|
||||
// Check if special alignment for macro-fusion is needed.
|
||||
bool MayNeedMacroFusionAlignment =
|
||||
|
@ -267,7 +267,7 @@ void BinaryFunction::markUnreachableBlocks() {
|
||||
|
||||
// Add all entries and landing pads as roots.
|
||||
for (auto *BB : BasicBlocks) {
|
||||
if (BB->isEntryPoint() || BB->isLandingPad()) {
|
||||
if (isEntryPoint(*BB) || BB->isLandingPad()) {
|
||||
Stack.push(BB);
|
||||
BB->markValid(true);
|
||||
continue;
|
||||
@ -307,7 +307,7 @@ std::pair<unsigned, uint64_t> BinaryFunction::eraseInvalidBBs() {
|
||||
if (BB->isValid()) {
|
||||
NewLayout.push_back(BB);
|
||||
} else {
|
||||
assert(!BB->isEntryPoint() && "all entry blocks must be valid");
|
||||
assert(!isEntryPoint(*BB) && "all entry blocks must be valid");
|
||||
++Count;
|
||||
Bytes += BC.computeCodeSize(BB->begin(), BB->end());
|
||||
}
|
||||
@ -396,7 +396,7 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
<< "\n Orc Section : " << getCodeSectionName()
|
||||
<< "\n LSDA : 0x" << Twine::utohexstr(getLSDAAddress())
|
||||
<< "\n IsSimple : " << IsSimple
|
||||
<< "\n IsMultiEntry: " << IsMultiEntry
|
||||
<< "\n IsMultiEntry: " << isMultiEntry()
|
||||
<< "\n IsSplit : " << isSplit()
|
||||
<< "\n BB Count : " << size();
|
||||
|
||||
@ -426,6 +426,14 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
if (hasCFG()) {
|
||||
OS << "\n Hash : " << Twine::utohexstr(computeHash());
|
||||
}
|
||||
if (isMultiEntry()) {
|
||||
OS << "\n Secondary Entry Points : ";
|
||||
auto Sep = "";
|
||||
for (auto &KV : SecondaryEntryPoints) {
|
||||
OS << Sep << KV.second->getName();
|
||||
Sep = ", ";
|
||||
}
|
||||
}
|
||||
if (FrameInstructions.size()) {
|
||||
OS << "\n CFI Instrs : " << FrameInstructions.size();
|
||||
}
|
||||
@ -465,8 +473,11 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
|
||||
// Print label if exists at this offset.
|
||||
auto LI = Labels.find(Offset);
|
||||
if (LI != Labels.end())
|
||||
if (LI != Labels.end()) {
|
||||
if (const auto *EntrySymbol = getSecondaryEntryPointSymbol(LI->second))
|
||||
OS << EntrySymbol->getName() << " (Entry Point):\n";
|
||||
OS << LI->second->getName() << ":\n";
|
||||
}
|
||||
|
||||
BC.printInstruction(OS, II.second, Offset, this);
|
||||
}
|
||||
@ -482,8 +493,12 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
<< BB->size() << " instructions, align : " << BB->getAlignment()
|
||||
<< ")\n";
|
||||
|
||||
if (BB->isEntryPoint())
|
||||
OS << " Entry Point\n";
|
||||
if (isEntryPoint(*BB)) {
|
||||
if (auto *EntrySymbol = getSecondaryEntryPointSymbol(*BB))
|
||||
OS << " Secondary Entry Point: " << EntrySymbol->getName() << '\n';
|
||||
else
|
||||
OS << " Entry Point\n";
|
||||
}
|
||||
|
||||
if (BB->isLandingPad())
|
||||
OS << " Landing Pad\n";
|
||||
@ -849,36 +864,26 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction,
|
||||
|
||||
MCSymbol *BinaryFunction::getOrCreateLocalLabel(uint64_t Address,
|
||||
bool CreatePastEnd) {
|
||||
// Check if there's already a registered label.
|
||||
auto Offset = Address - getAddress();
|
||||
const auto Offset = Address - getAddress();
|
||||
|
||||
if ((Offset == getSize()) && CreatePastEnd)
|
||||
return getFunctionEndLabel();
|
||||
|
||||
// Check if there's a global symbol registered at given address.
|
||||
// If so - reuse it since we want to keep the symbol value updated.
|
||||
if (Offset != 0) {
|
||||
if (auto *BD = BC.getBinaryDataAtAddress(Address)) {
|
||||
Labels[Offset] = BD->getSymbol();
|
||||
return BD->getSymbol();
|
||||
}
|
||||
}
|
||||
|
||||
auto LI = Labels.find(Offset);
|
||||
if (LI != Labels.end())
|
||||
return LI->second;
|
||||
|
||||
// For AArch64, check if this address is part of a constant island.
|
||||
if (MCSymbol *IslandSym = getOrCreateIslandAccess(Address)) {
|
||||
return IslandSym;
|
||||
if (BC.isAArch64()) {
|
||||
if (MCSymbol *IslandSym = getOrCreateIslandAccess(Address)) {
|
||||
return IslandSym;
|
||||
}
|
||||
}
|
||||
MCSymbol *Result;
|
||||
{
|
||||
auto L = BC.scopeLock();
|
||||
Result = BC.Ctx->createTempSymbol();
|
||||
}
|
||||
Labels[Offset] = Result;
|
||||
return Result;
|
||||
|
||||
auto *Label = BC.Ctx->createTempSymbol();
|
||||
Labels[Offset] = Label;
|
||||
|
||||
return Label;
|
||||
}
|
||||
|
||||
ErrorOr<ArrayRef<uint8_t>> BinaryFunction::getData() const {
|
||||
@ -920,7 +925,6 @@ void BinaryFunction::disassemble() {
|
||||
// Insert a label at the beginning of the function. This will be our first
|
||||
// basic block.
|
||||
Labels[0] = Ctx->createTempSymbol("BB0", false);
|
||||
addEntryPointAtOffset(0);
|
||||
|
||||
auto handlePCRelOperand =
|
||||
[&](MCInst &Instruction, uint64_t Address, uint64_t Size) {
|
||||
@ -1353,11 +1357,17 @@ void BinaryFunction::postProcessEntryPoints() {
|
||||
if (!isSimple())
|
||||
return;
|
||||
|
||||
for (auto Offset : EntryOffsets) {
|
||||
for (auto &KV : Labels) {
|
||||
auto *Label = KV.second;
|
||||
if (!getSecondaryEntryPointSymbol(Label))
|
||||
continue;
|
||||
|
||||
const auto Offset = KV.first;
|
||||
|
||||
// If we are at Offset 0 and there is no instruction associated with it,
|
||||
// this means this is an empty function. Just ignore. If we find an
|
||||
// instruction at this offset, this entry point is valid.
|
||||
if (getInstructionAtOffset(Offset) || !Offset) {
|
||||
if (!Offset || getInstructionAtOffset(Offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1718,8 +1728,6 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
|
||||
PrevBB = InsertBB;
|
||||
InsertBB = addBasicBlock(LI->first, LI->second,
|
||||
opts::PreserveBlocksAlignment && IsLastInstrNop);
|
||||
if (hasEntryPointAtOffset(Offset))
|
||||
InsertBB->setEntryPoint();
|
||||
if (PrevBB)
|
||||
updateOffset(LastInstrOffset);
|
||||
}
|
||||
@ -1933,7 +1941,6 @@ void BinaryFunction::postProcessCFG() {
|
||||
|
||||
// The final cleanup of intermediate structures.
|
||||
clearList(IgnoredBranches);
|
||||
clearList(EntryOffsets);
|
||||
|
||||
// Remove "Offset" annotations, unless we need an address-translation table
|
||||
// later. This has no cost, since annotations are allocated by a bumpptr
|
||||
@ -1985,44 +1992,6 @@ void BinaryFunction::removeTagsFromProfile() {
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFunction::updateReferences(const MCSymbol *From, const MCSymbol *To) {
|
||||
assert(CurrentState == State::Empty || CurrentState == State::Disassembled);
|
||||
assert(From && To && "invalid symbols");
|
||||
|
||||
for (auto I = Instructions.begin(), E = Instructions.end(); I != E; ++I) {
|
||||
auto &Inst = I->second;
|
||||
for (int I = 0, E = MCPlus::getNumPrimeOperands(Inst); I != E; ++I) {
|
||||
const MCSymbol *S = BC.MIB->getTargetSymbol(Inst, I);
|
||||
if (S == From)
|
||||
BC.MIB->setOperandToSymbolRef(Inst, I, To, 0, &*BC.Ctx, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFunction::addEntryPoint(uint64_t Address) {
|
||||
assert(containsAddress(Address) && "address does not belong to the function");
|
||||
assert(CurrentState == State::Empty || CurrentState == State::Disassembled);
|
||||
|
||||
const auto Offset = Address - getAddress();
|
||||
DEBUG(dbgs() << "BOLT-INFO: adding external entry point to function " << *this
|
||||
<< " at offset 0x" << Twine::utohexstr(Offset) << '\n');
|
||||
|
||||
auto *EntryBD = BC.getBinaryDataAtAddress(Address);
|
||||
auto *EntrySymbol = EntryBD ? EntryBD->getSymbol() : nullptr;
|
||||
auto Iter = Labels.find(Offset);
|
||||
const MCSymbol *OldSym = Iter != Labels.end() ? Iter->second : nullptr;
|
||||
if (!EntrySymbol) {
|
||||
EntrySymbol = getOrCreateLocalLabel(Address);
|
||||
}
|
||||
addEntryPointAtOffset(Offset);
|
||||
Labels.emplace(Offset, EntrySymbol);
|
||||
|
||||
BC.setSymbolToFunctionMap(EntrySymbol, this);
|
||||
if (OldSym != nullptr && EntrySymbol != OldSym) {
|
||||
updateReferences(OldSym, EntrySymbol);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFunction::removeConditionalTailCalls() {
|
||||
// Blocks to be appended at the end.
|
||||
std::vector<std::unique_ptr<BinaryBasicBlock>> NewBlocks;
|
||||
@ -2633,10 +2602,17 @@ void BinaryFunction::setTrapOnEntry() {
|
||||
clearList(IgnoredBranches);
|
||||
clearList(TakenBranches);
|
||||
|
||||
for (const auto EntryOffset : EntryOffsets) {
|
||||
auto addTrapAtOffset = [&](uint64_t Offset) {
|
||||
MCInst TrapInstr;
|
||||
BC.MIB->createTrap(TrapInstr);
|
||||
addInstruction(EntryOffset, std::move(TrapInstr));
|
||||
addInstruction(Offset, std::move(TrapInstr));
|
||||
};
|
||||
|
||||
addTrapAtOffset(0);
|
||||
for (auto &KV : getLabels()) {
|
||||
if (getSecondaryEntryPointSymbol(KV.second)) {
|
||||
addTrapAtOffset(KV.first);
|
||||
}
|
||||
}
|
||||
|
||||
TrapsOnEntry = true;
|
||||
@ -3093,8 +3069,8 @@ void BinaryFunction::postProcessBranches() {
|
||||
assert(validateCFG() && "invalid CFG");
|
||||
}
|
||||
|
||||
const MCSymbol *BinaryFunction::getSymbolForEntry(uint64_t EntryNum) const {
|
||||
if (EntryNum == 0)
|
||||
const MCSymbol *BinaryFunction::getSymbolForEntryID(uint64_t EntryID) const {
|
||||
if (EntryID == 0)
|
||||
return getSymbol();
|
||||
|
||||
if (!isMultiEntry())
|
||||
@ -3103,16 +3079,20 @@ const MCSymbol *BinaryFunction::getSymbolForEntry(uint64_t EntryNum) const {
|
||||
uint64_t NumEntries = 0;
|
||||
if (hasCFG()) {
|
||||
for (auto *BB : BasicBlocks) {
|
||||
if (!BB->isEntryPoint())
|
||||
auto *EntrySymbol = getSecondaryEntryPointSymbol(*BB);
|
||||
if (!EntrySymbol)
|
||||
continue;
|
||||
if (NumEntries == EntryNum)
|
||||
return BB->getLabel();
|
||||
if (NumEntries == EntryID)
|
||||
return EntrySymbol;
|
||||
++NumEntries;
|
||||
}
|
||||
} else {
|
||||
for (auto &KV : Labels) {
|
||||
if (NumEntries == EntryNum)
|
||||
return KV.second;
|
||||
auto *EntrySymbol = getSecondaryEntryPointSymbol(KV.second);
|
||||
if (!EntrySymbol)
|
||||
continue;
|
||||
if (NumEntries == EntryID)
|
||||
return EntrySymbol;
|
||||
++NumEntries;
|
||||
}
|
||||
}
|
||||
@ -3120,26 +3100,30 @@ const MCSymbol *BinaryFunction::getSymbolForEntry(uint64_t EntryNum) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t BinaryFunction::getEntryForSymbol(const MCSymbol *EntrySymbol) const {
|
||||
uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const {
|
||||
if (!isMultiEntry())
|
||||
return 0;
|
||||
|
||||
for (const auto *Symbol : getSymbols())
|
||||
if (Symbol == EntrySymbol)
|
||||
for (const auto *FunctionSymbol : getSymbols())
|
||||
if (FunctionSymbol == Symbol)
|
||||
return 0;
|
||||
|
||||
// Check all secondary entries available as either basic blocks or lables.
|
||||
uint64_t NumEntries = 0;
|
||||
for (const auto *BB : BasicBlocks) {
|
||||
if (!BB->isEntryPoint())
|
||||
auto *EntrySymbol = getSecondaryEntryPointSymbol(*BB);
|
||||
if (!EntrySymbol)
|
||||
continue;
|
||||
if (BB->getLabel() == EntrySymbol)
|
||||
if (EntrySymbol == Symbol)
|
||||
return NumEntries;
|
||||
++NumEntries;
|
||||
}
|
||||
NumEntries = 0;
|
||||
for (auto &KV : Labels) {
|
||||
if (KV.second == EntrySymbol)
|
||||
auto *EntrySymbol = getSecondaryEntryPointSymbol(KV.second);
|
||||
if (!EntrySymbol)
|
||||
continue;
|
||||
if (EntrySymbol == Symbol)
|
||||
return NumEntries;
|
||||
++NumEntries;
|
||||
}
|
||||
@ -3157,7 +3141,7 @@ BinaryFunction::BasicBlockOrderType BinaryFunction::dfs() const {
|
||||
// NB: we rely on the original order of entries to match.
|
||||
for (auto BBI = layout_rbegin(); BBI != layout_rend(); ++BBI) {
|
||||
auto *BB = *BBI;
|
||||
if (BB->isEntryPoint())
|
||||
if (isEntryPoint(*BB))
|
||||
Stack.push(BB);
|
||||
BB->setLayoutIndex(BinaryBasicBlock::InvalidIndex);
|
||||
}
|
||||
|
@ -244,6 +244,12 @@ private:
|
||||
/// Offsets of indirect branches with unknown destinations.
|
||||
std::set<uint64_t> UnknownIndirectBranchOffsets;
|
||||
|
||||
/// A set of local and global symbols corresponding to secondary entry points.
|
||||
/// Each additional function entry point has a corresponding entry in the map.
|
||||
/// The key is a local symbol corresponding to a basic block and the value
|
||||
/// is a global symbol corresponding to an external entry point.
|
||||
std::unordered_map<const MCSymbol *, MCSymbol *> SecondaryEntryPoints;
|
||||
|
||||
/// False if the function is too complex to reconstruct its control
|
||||
/// flow graph.
|
||||
/// In relocation mode we still disassemble and re-assemble such functions.
|
||||
@ -267,9 +273,6 @@ private:
|
||||
/// True if the function uses DW_CFA_GNU_args_size CFIs.
|
||||
bool UsesGnuArgsSize{false};
|
||||
|
||||
/// True if the function has more than one entry point.
|
||||
bool IsMultiEntry{false};
|
||||
|
||||
/// True if the function might have a profile available externally.
|
||||
/// Used to check if processing of the function is required under certain
|
||||
/// conditions.
|
||||
@ -404,9 +407,6 @@ private:
|
||||
/// Synchronize branch instructions with CFG.
|
||||
void postProcessBranches();
|
||||
|
||||
/// Temporary holder of offsets that are potentially entry points.
|
||||
std::unordered_set<uint64_t> EntryOffsets;
|
||||
|
||||
/// The address offset where we emitted the constant island, that is, the
|
||||
/// chunk of data in the function code area (AArch only)
|
||||
int64_t OutputDataOffset{0};
|
||||
@ -559,11 +559,13 @@ private:
|
||||
Aliases.push_back(std::move(NewName));
|
||||
}
|
||||
|
||||
/// Return label at a given \p Address in the function. If the label does
|
||||
/// Return a label at a given \p Address in the function. If the label does
|
||||
/// not exist - create it. Assert if the \p Address does not belong to
|
||||
/// the function. If \p CreatePastEnd is true, then return the function
|
||||
/// end label when the \p Address points immediately past the last byte
|
||||
/// of the function.
|
||||
/// NOTE: the function always returns a local (temp) symbol, even if there's
|
||||
/// a global symbol that corresponds to an entry at this address.
|
||||
MCSymbol *getOrCreateLocalLabel(uint64_t Address, bool CreatePastEnd = false);
|
||||
|
||||
/// Register an entry point at a given \p Offset into the function.
|
||||
@ -576,13 +578,30 @@ private:
|
||||
Islands.CodeOffsets.emplace(Offset);
|
||||
}
|
||||
|
||||
/// Register an entry point at a given \p Offset into the function.
|
||||
/// Register secondary entry point at a given \p Offset into the function.
|
||||
/// Return global symbol for use by extern function references.
|
||||
MCSymbol *addEntryPointAtOffset(uint64_t Offset) {
|
||||
EntryOffsets.emplace(Offset);
|
||||
IsMultiEntry = (Offset == 0 ? IsMultiEntry : true);
|
||||
MCSymbol *Sym = getOrCreateLocalLabel(getAddress() + Offset);
|
||||
BC.setSymbolToFunctionMap(Sym, this);
|
||||
return Sym;
|
||||
assert(Offset && "cannot add primary entry point");
|
||||
assert(CurrentState == State::Empty || CurrentState == State::Disassembled);
|
||||
|
||||
const uint64_t EntryPointAddress = getAddress() + Offset;
|
||||
MCSymbol *LocalSymbol = getOrCreateLocalLabel(EntryPointAddress);
|
||||
|
||||
MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(LocalSymbol);
|
||||
if (EntrySymbol)
|
||||
return EntrySymbol;
|
||||
|
||||
if (auto *EntryBD = BC.getBinaryDataAtAddress(EntryPointAddress)) {
|
||||
EntrySymbol = EntryBD->getSymbol();
|
||||
} else {
|
||||
EntrySymbol = BC.Ctx->getOrCreateSymbol(
|
||||
"__ENTRY_0x" + Twine::utohexstr(Offset) + "_" + getOneName());
|
||||
}
|
||||
SecondaryEntryPoints[LocalSymbol] = EntrySymbol;
|
||||
|
||||
BC.setSymbolToFunctionMap(EntrySymbol, this);
|
||||
|
||||
return EntrySymbol;
|
||||
}
|
||||
|
||||
/// Register an internal offset in a function referenced from outside.
|
||||
@ -596,19 +615,12 @@ private:
|
||||
return !ExternallyReferencedOffsets.empty();
|
||||
}
|
||||
|
||||
/// Update all \p From references in the code to refer to \p To. Used
|
||||
/// in disassembled state only.
|
||||
void updateReferences(const MCSymbol *From, const MCSymbol *To);
|
||||
|
||||
/// This is called in disassembled state.
|
||||
void addEntryPoint(uint64_t Address);
|
||||
|
||||
/// Return an entry ID corresponding to a symbol known to belong to
|
||||
/// the function.
|
||||
///
|
||||
/// Prefer to use BinaryContext::getFunctionForSymbol(EntrySymbol, &ID)
|
||||
/// instead of calling this function directly.
|
||||
uint64_t getEntryForSymbol(const MCSymbol *EntrySymbol) const;
|
||||
uint64_t getEntryIDForSymbol(const MCSymbol *EntrySymbol) const;
|
||||
|
||||
void setParentFunction(BinaryFunction *BF) {
|
||||
assert((!ParentFunction || ParentFunction == BF) &&
|
||||
@ -620,13 +632,6 @@ private:
|
||||
Fragments.insert(BF);
|
||||
}
|
||||
|
||||
/// Return true if there is a registered entry point at a given offset
|
||||
/// into the function.
|
||||
bool hasEntryPointAtOffset(uint64_t Offset) {
|
||||
assert(!EntryOffsets.empty() && "entry points uninitialized or destroyed");
|
||||
return EntryOffsets.count(Offset);
|
||||
}
|
||||
|
||||
void addInstruction(uint64_t Offset, MCInst &&Instruction) {
|
||||
Instructions.emplace(Offset, std::forward<MCInst>(Instruction));
|
||||
}
|
||||
@ -1113,9 +1118,35 @@ public:
|
||||
SymbolListTy &getSymbols() { return Symbols; }
|
||||
const SymbolListTy &getSymbols() const { return Symbols; }
|
||||
|
||||
/// If a local symbol \p BBLabel corresponds to a basic block that is a
|
||||
/// secondary entry point into the function, then return a global symbol
|
||||
/// that represents the secondary entry point. Otherwise return nullptr.
|
||||
MCSymbol *getSecondaryEntryPointSymbol(const MCSymbol *BBLabel) const {
|
||||
auto I = SecondaryEntryPoints.find(BBLabel);
|
||||
if (I == SecondaryEntryPoints.end())
|
||||
return nullptr;
|
||||
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// If the basic block serves as a secondary entry point to the function,
|
||||
/// return a global symbol representing the entry. Otherwise return nullptr.
|
||||
MCSymbol *getSecondaryEntryPointSymbol(const BinaryBasicBlock &BB) const {
|
||||
return getSecondaryEntryPointSymbol(BB.getLabel());
|
||||
}
|
||||
|
||||
/// Return true if the basic block is an entry point into the function
|
||||
/// (either primary or secondary).
|
||||
bool isEntryPoint(const BinaryBasicBlock &BB) const {
|
||||
if (&BB == BasicBlocks.front())
|
||||
return true;
|
||||
return getSecondaryEntryPointSymbol(BB);
|
||||
}
|
||||
|
||||
|
||||
/// Return MC symbol corresponding to an enumerated entry for multiple-entry
|
||||
/// functions.
|
||||
const MCSymbol *getSymbolForEntry(uint64_t EntryNum) const;
|
||||
const MCSymbol *getSymbolForEntryID(uint64_t EntryNum) const;
|
||||
|
||||
MCSymbol *getColdSymbol() {
|
||||
if (ColdSymbol)
|
||||
@ -1326,7 +1357,7 @@ public:
|
||||
|
||||
/// Return true if the function has more than one entry point.
|
||||
bool isMultiEntry() const {
|
||||
return IsMultiEntry;
|
||||
return !SecondaryEntryPoints.empty();
|
||||
}
|
||||
|
||||
/// Return true if the function might have a profile available externally,
|
||||
@ -1489,6 +1520,28 @@ public:
|
||||
return BB;
|
||||
}
|
||||
|
||||
/// Add basic block \BB as an entry point to the function. Return global
|
||||
/// symbol associated with the entry.
|
||||
MCSymbol *addEntryPoint(const BinaryBasicBlock &BB) {
|
||||
assert(CurrentState == State::CFG);
|
||||
|
||||
if (&BB == BasicBlocks.front())
|
||||
return getSymbol();
|
||||
|
||||
auto *EntrySymbol = getSecondaryEntryPointSymbol(BB);
|
||||
if (EntrySymbol)
|
||||
return EntrySymbol;
|
||||
|
||||
EntrySymbol =
|
||||
BC.Ctx->getOrCreateSymbol("__ENTRY_" + BB.getLabel()->getName());
|
||||
|
||||
SecondaryEntryPoints[BB.getLabel()] = EntrySymbol;
|
||||
|
||||
BC.setSymbolToFunctionMap(EntrySymbol, this);
|
||||
|
||||
return EntrySymbol;
|
||||
}
|
||||
|
||||
/// Mark all blocks that are unreachable from a root (entry point
|
||||
/// or landing pad) as invalid.
|
||||
void markUnreachableBlocks();
|
||||
|
@ -247,7 +247,7 @@ LongJmpPass::replaceTargetWithStub(BinaryBasicBlock &BB, MCInst &Inst,
|
||||
assert(TgtBB == nullptr);
|
||||
StubBB->setIsCold(BB.isCold());
|
||||
// Set as entry point because this block is valid but we have no preds
|
||||
StubBB->setEntryPoint(true);
|
||||
StubBB->getFunction()->addEntryPoint(*StubBB);
|
||||
}
|
||||
}
|
||||
BC.MIB->replaceBranchTarget(Inst, StubSymbol, BC.Ctx.get());
|
||||
|
@ -124,7 +124,7 @@ ProfileReader::parseFunctionProfile(BinaryFunction &BF,
|
||||
bool IsFunction = Callee ? true : false;
|
||||
const MCSymbol *CalleeSymbol = nullptr;
|
||||
if (IsFunction) {
|
||||
CalleeSymbol = Callee->getSymbolForEntry(YamlCSI.EntryDiscriminator);
|
||||
CalleeSymbol = Callee->getSymbolForEntryID(YamlCSI.EntryDiscriminator);
|
||||
}
|
||||
StringRef Name = CalleeSymbol ? CalleeSymbol->getName() : "<unknown>";
|
||||
BF.getAllCallSites().emplace_back(
|
||||
|
@ -5,5 +5,8 @@
|
||||
# RUN: | FileCheck %s
|
||||
|
||||
CHECK-NOT: BOLT-WARNING: CFG invalid in XYZ @ .LBB0
|
||||
|
||||
CHECK: Binary Function "XYZ"
|
||||
CHECK: 0000000a: jne FUNCat0x4004e9
|
||||
|
||||
CHECK: .Ltmp0 (1 instructions, align : 1)
|
||||
CHECK-NEXT: Secondary Entry Point: FUNCat0x4004e9
|
||||
|
Loading…
x
Reference in New Issue
Block a user