[llvm] [BOLT] Split unmarked tail code after CFI-bounded functions into separate functions (PR #176173)
Paschalis Mpeis via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 09:58:14 PDT 2026
================
@@ -2075,6 +2068,164 @@ void RewriteInstance::disassemblePLT() {
}
}
+namespace {
+
+/// True when the predecessor body ends at its FDE boundary, so trailing bytes
+/// are outside both symtab size and unwind info:
+/// (1) __BOLT_FDE_FUNC* (FDE with no symtab entry), or
+/// (2) a normal symbol whose size equals its FDE address range.
+bool isCFIBoundedTailPredecessor(const BinaryFunction &BF,
+ const CFIReaderWriter &CFI) {
+ if (BF.getOneName().starts_with("__BOLT_FDE_FUNC"))
+ return true;
+ auto FDEI = CFI.getFDEs().find(BF.getAddress());
+ if (FDEI == CFI.getFDEs().end())
+ return false;
+ return FDEI->second->getAddressRange() == BF.getSize();
+}
+
+/// AArch64 padding / filler instructions that may appear in slack but are not
+/// standalone callable functions.
+bool isAArch64TailPaddingInst(const BinaryContext &BC, const MCInst &Inst) {
+ if (BC.MIB->isNoop(Inst) || BC.MIB->isTrap(Inst))
+ return true;
+ return false;
+}
+
+/// True if the decoded tail looks like real callable code, not padding.
+/// Expects trailing filler to have already been trimmed, so the last
+/// instruction must be the tail's terminator.
+bool isValidAArch64UnmarkedTail(const BinaryContext &BC,
+ ArrayRef<MCInst> Insts) {
+ if (Insts.empty())
+ return false;
+
+ // Expect a callable snippet; inlined tails end with ret.
+ return BC.MIB->isReturn(Insts.back());
+}
+
+/// Disassemble a prefix of [TailStart, TailStart + TrailingExtent) and return
+/// the length of the callable tail. Trailing filler instructions (nop/trap)
+/// after the terminator are trimmed and treated as slack, and any remaining
+/// bytes in the range must be zero padding.
+/// Returns 0 if the region is not valid unmarked code.
+uint64_t
+measureAArch64UnmarkedTail(BinaryContext &BC, const BinaryFunction &Pred,
+ DenseMap<uint64_t, MarkerSymType> &MarkerSyms,
+ uint64_t TailStart, uint64_t TrailingExtent) {
+ auto hasDataMarkerAt = [&MarkerSyms](uint64_t Address) {
+ auto It = MarkerSyms.find(Address);
+ return It != MarkerSyms.end() && It->second == MarkerSymType::DATA;
+ };
+
+ // Pred was registered from an executable section during symbol/FDE discovery.
+ BinarySection &Section = *Pred.getOriginSection();
+
+ // adjustFunctionBoundaries() set Pred->MaxSize so [Pred, Pred+MaxSize) fits
+ // in the section and stops at the next symbol/function.
+ if (!Section.containsRange(TailStart, TrailingExtent))
+ return 0;
+
+ StringRef Contents = Section.getContents();
+ const uint64_t SectionOffset = TailStart - Section.getAddress();
+ const uint8_t *Bytes =
+ reinterpret_cast<const uint8_t *>(Contents.data()) + SectionOffset;
+
+ SmallVector<MCInst, 4> Insts;
+ SmallVector<uint64_t, 4> InstSizes;
+ uint64_t CodeLen = 0;
+ while (CodeLen < TrailingExtent) {
+ if (hasDataMarkerAt(TailStart + CodeLen))
+ return 0;
+ if (Pred.isInConstantIsland(TailStart + CodeLen))
+ return 0;
+
+ MCInst Inst;
+ uint64_t Size = 0;
+ ArrayRef<uint8_t> Slice(Bytes + CodeLen, TrailingExtent - CodeLen);
+ if (!BC.SymbolicDisAsm->getInstruction(Inst, Size, Slice,
+ TailStart + CodeLen, nulls()) ||
+ !Size)
+ break;
+ Insts.push_back(Inst);
+ InstSizes.push_back(Size);
+ CodeLen += Size;
+ }
+
+ // Ignore trailing filler (nop/trap) after the terminator. The filler is
+ // treated as slack, just like the zero padding checked below, so real
+ // binaries with post-ret padding are still recognized.
+ size_t CallableInsts = Insts.size();
+ while (CallableInsts > 0 &&
+ isAArch64TailPaddingInst(BC, Insts[CallableInsts - 1]))
+ --CallableInsts;
----------------
paschalis-mpeis wrote:
nit: could init `TailLen=CodeLen` and subtract instr sizes in this loop, avoiding the loop below.
https://github.com/llvm/llvm-project/pull/176173
More information about the llvm-commits
mailing list