[llvm-branch-commits] [llvm] [BOLT][BTI] Patch LLD-generated PLTs to contain BTI landing pad (PR #173245)
Peter Waller via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jan 6 02:05:25 PST 2026
================
@@ -1669,6 +1669,67 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
return Base + Offset;
}
+ /// PLT entry before patching:
+ ///
+ /// adrp x16, Page(&(.got.plt[n]))
+ /// ldr x17, [x16, Offset(&(.got.plt[n]))]
+ /// add x16, x16, Offset(&(.got.plt[n]))
+ /// br x17
+ /// nop
+ /// nop
+ ///
+ /// PLT entry after patching:
+ ///
+ /// bti c
+ /// adrp x16, Page(&(.got.plt[n]))
+ /// ldr x17, [x16, Offset(&(.got.plt[n]))]
+ /// add x16, x16, Offset(&(.got.plt[n]))
+ /// br x17
+ /// nop
+ ///
+ /// Safety considerations:
+ ///
+ /// The PLT entry will become incorrect if shifting the ADRP by one
+ /// instruction (4 bytes) moves it across a page boundary.
+ ///
+ /// The PLT entry is 24 bytes, and page size is 4096 (or 16384) bytes.
+ /// Their GCD is 8 bytes, meaning that shifting the ADRP is safe, as long as
+ /// it is shifted by less than 8 bytes.
+ ///
+ /// If the PLT entry does not contain extra nops, this function will create an
+ /// error. This can happen in binaries linked using BFD.
+ void patchPLTEntryForBTI(BinaryFunction &PLTFunction, MCInst &Call) override {
+ BinaryContext &BC = PLTFunction.getBinaryContext();
+ assert(PLTFunction.isPLTFunction() &&
+ "patchPLTEntryForBTI called on a non-PLT function");
+ // Checking if the PLT entry already starts with the BTI needed for Call.
+ auto FirstBBI = PLTFunction.begin();
+ auto FirstII = FirstBBI->begin();
+ assert(FirstII != FirstBBI->end() && "Cannot patch empty PLT entry");
+ if (isCallCoveredByBTI(Call, *FirstII))
+ return;
+ // Checking if there are extra nops at the end. If not, BOLT cannot patch
+ // the PLT entry.
+ auto LastBBI = std::prev(PLTFunction.end());
+ auto LastII = std::prev(LastBBI->end());
+ if (!isNoop(*LastII)) {
+ errs() << "BOLT-ERROR: Cannot patch PLT entry "
+ << PLTFunction.getPrintName()
+ << " to have a BTI landing pad. Relink the workload using LLD.\n";
+ exit(1);
+ }
+ // If the PLT does not have a BTI, and it has nops, create a new instruction
+ // sequence to patch the entry with.
+ InstructionListType NewPLTSeq;
+ MCInst BTIInst;
+ createBTI(BTIInst, BTIKind::C);
+ NewPLTSeq.push_back(BTIInst);
+ for (auto II = FirstBBI->begin(); II != FirstBBI->end(); ++II) {
+ NewPLTSeq.push_back(*II);
+ }
+ BC.createInstructionPatch(PLTFunction.getAddress(), NewPLTSeq);
----------------
peterwaller-arm wrote:
This writes all of the original instructions out (including the trailing nops), so is the patch size one larger than intended? Assuming this works as is, it is not a problem; but might be good to have a short comment explaining why it works or ensure the patch size no larger than the original entry.
https://github.com/llvm/llvm-project/pull/173245
More information about the llvm-branch-commits
mailing list