[BOLT] Refactor interface for creating instruction patches. NFCI (#129404)

Add BinaryContext::createInstructionPatch() interface for patching parts
of the original binary with new instruction sequences. Refactor
PatchEntries pass to use the new interface.
This commit is contained in:
Maksim Panchenko
2025-03-01 19:20:17 -08:00
committed by GitHub
parent a0540e6c98
commit 5a11912ece
4 changed files with 44 additions and 14 deletions

View File

@@ -537,6 +537,17 @@ public:
BinaryFunction *createInjectedBinaryFunction(const std::string &Name,
bool IsSimple = true);
/// Patch the original binary contents at address \p Address with a sequence
/// of instructions from the \p Instructions list. The callee is responsible
/// for checking that the sequence doesn't cross any function or section
/// boundaries.
///
/// Optional \p Name can be assigned to the patch. The name will be emitted to
/// the symbol table at \p Address.
BinaryFunction *createInstructionPatch(uint64_t Address,
InstructionListType &Instructions,
const Twine &Name = "");
std::vector<BinaryFunction *> &getInjectedBinaryFunctions() {
return InjectedBinaryFunctions;
}

View File

@@ -26,8 +26,6 @@ class PatchEntries : public BinaryFunctionPass {
struct Patch {
const MCSymbol *Symbol;
uint64_t Address;
uint64_t FileOffset;
BinarySection *Section;
};
public:

View File

@@ -2400,6 +2400,32 @@ BinaryContext::createInjectedBinaryFunction(const std::string &Name,
return BF;
}
BinaryFunction *BinaryContext::createInstructionPatch(
uint64_t Address, InstructionListType &Instructions, const Twine &Name) {
ErrorOr<BinarySection &> Section = getSectionForAddress(Address);
assert(Section && "cannot get section for patching");
assert(Section->hasSectionRef() && Section->isText() &&
"can only patch input file code sections");
const uint64_t FileOffset =
Section->getInputFileOffset() + Address - Section->getAddress();
std::string PatchName = Name.str();
if (PatchName.empty()) {
// Assign unique name to the patch.
static uint64_t N = 0;
PatchName = "__BP_" + std::to_string(N++);
}
BinaryFunction *PBF = createInjectedBinaryFunction(PatchName);
PBF->setOutputAddress(Address);
PBF->setFileOffset(FileOffset);
PBF->setOriginSection(&Section.get());
PBF->addBasicBlock()->addInstructions(Instructions);
return PBF;
}
std::pair<size_t, size_t>
BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {
// Adjust branch instruction to match the current layout.

View File

@@ -83,9 +83,8 @@ Error PatchEntries::runOnFunctions(BinaryContext &BC) {
return false;
}
PendingPatches.emplace_back(Patch{Symbol, Function.getAddress() + Offset,
Function.getFileOffset() + Offset,
Function.getOriginSection()});
PendingPatches.emplace_back(
Patch{Symbol, Function.getAddress() + Offset});
NextValidByte = Offset + PatchSize;
if (NextValidByte > Function.getMaxSize()) {
if (opts::Verbosity >= 1)
@@ -118,16 +117,12 @@ Error PatchEntries::runOnFunctions(BinaryContext &BC) {
}
for (Patch &Patch : PendingPatches) {
BinaryFunction *PatchFunction = BC.createInjectedBinaryFunction(
// Add instruction patch to the binary.
InstructionListType Instructions;
BC.MIB->createLongTailCall(Instructions, Patch.Symbol, BC.Ctx.get());
BinaryFunction *PatchFunction = BC.createInstructionPatch(
Patch.Address, Instructions,
NameResolver::append(Patch.Symbol->getName(), ".org.0"));
// Force the function to be emitted at the given address.
PatchFunction->setOutputAddress(Patch.Address);
PatchFunction->setFileOffset(Patch.FileOffset);
PatchFunction->setOriginSection(Patch.Section);
InstructionListType Seq;
BC.MIB->createLongTailCall(Seq, Patch.Symbol, BC.Ctx.get());
PatchFunction->addBasicBlock()->addInstructions(Seq);
// Verify the size requirements.
uint64_t HotSize, ColdSize;