[BOLT] Run PatchEntries pass before LongJmp (#137236)

With --force-patch option, every original function entry point is
overwritten with a trampoline to a new version of the function to
prevent the execution of the original code.

If the function size is too small for the trampoline code, we are forced
to bail out on rewriting the function. That presented a problem on
AArch64 due to LongJmp pass that assumed the presence of the new copy of
the function. If the new copy was not emitted it could have lead to a
relocation overflow.

Run PatchEntries pass before LongJmp and make the latter aware of the
functions that are not going to be emitted. Make --force-patch option
behavior on AArch64 consistent with other architectures.
This commit is contained in:
Maksim Panchenko
2025-05-01 15:09:09 -07:00
committed by GitHub
parent 472c211f58
commit 7d6fda4fd3
2 changed files with 5 additions and 16 deletions

View File

@@ -98,21 +98,10 @@ Error PatchEntries::runOnFunctions(BinaryContext &BC) {
});
if (!Success) {
// We can't change output layout for AArch64 due to LongJmp pass
if (BC.isAArch64()) {
if (opts::ForcePatch) {
BC.errs() << "BOLT-ERROR: unable to patch entries in " << Function
<< "\n";
return createFatalBOLTError("");
}
continue;
}
// If the original function entries cannot be patched, then we cannot
// safely emit new function body.
BC.errs() << "BOLT-WARNING: failed to patch entries in " << Function
<< ". The function will not be optimized.\n";
<< ". The function will not be optimized\n";
Function.setIgnored();
continue;
}

View File

@@ -497,6 +497,10 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
// memory profiling data.
Manager.registerPass(std::make_unique<ReorderData>());
// Patch original function entries
if (BC.HasRelocations)
Manager.registerPass(std::make_unique<PatchEntries>());
if (BC.isAArch64()) {
Manager.registerPass(
std::make_unique<ADRRelaxationPass>(PrintAdrRelaxation));
@@ -524,10 +528,6 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
// Assign each function an output section.
Manager.registerPass(std::make_unique<AssignSections>());
// Patch original function entries
if (BC.HasRelocations)
Manager.registerPass(std::make_unique<PatchEntries>());
// This pass turns tail calls into jumps which makes them invisible to
// function reordering. It's unsafe to use any CFG or instruction analysis
// after this point.