Files
clang-p2996/bolt/lib/Passes/RetpolineInsertion.cpp
spaette 1a2f83366b [BOLT] Fix typos (#68121)
Closes https://github.com/llvm/llvm-project/issues/63097

Before merging please make sure the change to
bolt/include/bolt/Passes/StokeInfo.h is correct.

bolt/include/bolt/Passes/StokeInfo.h

```diff
  //  This Pass solves the two major problems to use the Stoke program without
- //  proting its code:
+ //  probing its code:
```

I'm still not happy about the awkward wording in this comment.

bolt/include/bolt/Passes/FixRelaxationPass.h

```
$ ed -s bolt/include/bolt/Passes/FixRelaxationPass.h <<<'9,12p'
// This file declares the FixRelaxations class, which locates instructions with
// wrong targets and fixes them. Such problems usually occures when linker
// relaxes (changes) instructions, but doesn't fix relocations types properly
// for them.
$
```


bolt/docs/doxygen.cfg.in
bolt/include/bolt/Core/BinaryContext.h
bolt/include/bolt/Core/BinaryFunction.h
bolt/include/bolt/Core/BinarySection.h
bolt/include/bolt/Core/DebugData.h
bolt/include/bolt/Core/DynoStats.h
bolt/include/bolt/Core/Exceptions.h
bolt/include/bolt/Core/MCPlusBuilder.h
bolt/include/bolt/Core/Relocation.h
bolt/include/bolt/Passes/FixRelaxationPass.h
bolt/include/bolt/Passes/InstrumentationSummary.h
bolt/include/bolt/Passes/ReorderAlgorithm.h
bolt/include/bolt/Passes/StackReachingUses.h
bolt/include/bolt/Passes/StokeInfo.h
bolt/include/bolt/Passes/TailDuplication.h
bolt/include/bolt/Profile/DataAggregator.h
bolt/include/bolt/Profile/DataReader.h
bolt/lib/Core/BinaryContext.cpp
bolt/lib/Core/BinarySection.cpp
bolt/lib/Core/DebugData.cpp
bolt/lib/Core/DynoStats.cpp
bolt/lib/Core/Relocation.cpp
bolt/lib/Passes/Instrumentation.cpp
bolt/lib/Passes/JTFootprintReduction.cpp
bolt/lib/Passes/ReorderData.cpp
bolt/lib/Passes/RetpolineInsertion.cpp
bolt/lib/Passes/ShrinkWrapping.cpp
bolt/lib/Passes/TailDuplication.cpp
bolt/lib/Rewrite/BoltDiff.cpp
bolt/lib/Rewrite/DWARFRewriter.cpp
bolt/lib/Rewrite/RewriteInstance.cpp
bolt/lib/Utils/CommandLineOpts.cpp
bolt/runtime/instr.cpp
bolt/test/AArch64/got-ld64-relaxation.test
bolt/test/AArch64/unmarked-data.test
bolt/test/X86/Inputs/dwarf5-cu-no-debug-addr-helper.s
bolt/test/X86/Inputs/linenumber.cpp
bolt/test/X86/double-jump.test
bolt/test/X86/dwarf5-call-pc-function-null-check.test
bolt/test/X86/dwarf5-split-dwarf4-monolithic.test
bolt/test/X86/dynrelocs.s
bolt/test/X86/fallthrough-to-noop.test
bolt/test/X86/tail-duplication-cache.s
bolt/test/runtime/X86/instrumentation-ind-calls.s
2023-11-09 11:29:46 -08:00

338 lines
11 KiB
C++

//===- bolt/Passes/RetpolineInsertion.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements RetpolineInsertion class, which replaces indirect
// branches (calls and jumps) with calls to retpolines to protect against branch
// target injection attacks.
// A unique retpoline is created for each register holding the address of the
// callee, if the callee address is in memory %r11 is used if available to
// hold the address of the callee before calling the retpoline, otherwise an
// address pattern specific retpoline is called where the callee address is
// loaded inside the retpoline.
// The user can determine when to assume %r11 available using r11-availability
// option, by default %r11 is assumed not available.
// Adding lfence instruction to the body of the speculate code is enabled by
// default and can be controlled by the user using retpoline-lfence option.
//
//===----------------------------------------------------------------------===//
#include "bolt/Passes/RetpolineInsertion.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "bolt-retpoline"
using namespace llvm;
using namespace bolt;
namespace opts {
extern cl::OptionCategory BoltCategory;
llvm::cl::opt<bool> InsertRetpolines("insert-retpolines",
cl::desc("run retpoline insertion pass"),
cl::cat(BoltCategory));
llvm::cl::opt<bool>
RetpolineLfence("retpoline-lfence",
cl::desc("determine if lfence instruction should exist in the retpoline"),
cl::init(true),
cl::ZeroOrMore,
cl::Hidden,
cl::cat(BoltCategory));
cl::opt<RetpolineInsertion::AvailabilityOptions> R11Availability(
"r11-availability",
cl::desc("determine the availability of r11 before indirect branches"),
cl::init(RetpolineInsertion::AvailabilityOptions::NEVER),
cl::values(clEnumValN(RetpolineInsertion::AvailabilityOptions::NEVER,
"never", "r11 not available"),
clEnumValN(RetpolineInsertion::AvailabilityOptions::ALWAYS,
"always", "r11 available before calls and jumps"),
clEnumValN(RetpolineInsertion::AvailabilityOptions::ABI, "abi",
"r11 available before calls but not before jumps")),
cl::ZeroOrMore, cl::cat(BoltCategory));
} // namespace opts
namespace llvm {
namespace bolt {
// Retpoline function structure:
// BB0: call BB2
// BB1: pause
// lfence
// jmp BB1
// BB2: mov %reg, (%rsp)
// ret
// or
// BB2: push %r11
// mov Address, %r11
// mov %r11, 8(%rsp)
// pop %r11
// ret
BinaryFunction *createNewRetpoline(BinaryContext &BC,
const std::string &RetpolineTag,
const IndirectBranchInfo &BrInfo,
bool R11Available) {
auto &MIB = *BC.MIB;
MCContext &Ctx = *BC.Ctx.get();
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Creating a new retpoline function["
<< RetpolineTag << "]\n");
BinaryFunction *NewRetpoline =
BC.createInjectedBinaryFunction(RetpolineTag, true);
std::vector<std::unique_ptr<BinaryBasicBlock>> NewBlocks(3);
for (int I = 0; I < 3; I++) {
MCSymbol *Symbol =
Ctx.createNamedTempSymbol(Twine(RetpolineTag + "_BB" + to_string(I)));
NewBlocks[I] = NewRetpoline->createBasicBlock(Symbol);
NewBlocks[I].get()->setCFIState(0);
}
BinaryBasicBlock &BB0 = *NewBlocks[0].get();
BinaryBasicBlock &BB1 = *NewBlocks[1].get();
BinaryBasicBlock &BB2 = *NewBlocks[2].get();
BB0.addSuccessor(&BB2, 0, 0);
BB1.addSuccessor(&BB1, 0, 0);
// Build BB0
MCInst DirectCall;
MIB.createDirectCall(DirectCall, BB2.getLabel(), &Ctx, /*IsTailCall*/ false);
BB0.addInstruction(DirectCall);
// Build BB1
MCInst Pause;
MIB.createPause(Pause);
BB1.addInstruction(Pause);
if (opts::RetpolineLfence) {
MCInst Lfence;
MIB.createLfence(Lfence);
BB1.addInstruction(Lfence);
}
InstructionListType Seq;
MIB.createShortJmp(Seq, BB1.getLabel(), &Ctx);
BB1.addInstructions(Seq.begin(), Seq.end());
// Build BB2
if (BrInfo.isMem()) {
if (R11Available) {
MCInst StoreToStack;
MIB.createSaveToStack(StoreToStack, MIB.getStackPointer(), 0,
MIB.getX86R11(), 8);
BB2.addInstruction(StoreToStack);
} else {
MCInst PushR11;
MIB.createPushRegister(PushR11, MIB.getX86R11(), 8);
BB2.addInstruction(PushR11);
MCInst LoadCalleeAddrs;
const IndirectBranchInfo::MemOpInfo &MemRef = BrInfo.Memory;
MIB.createLoad(LoadCalleeAddrs, MemRef.BaseRegNum, MemRef.ScaleImm,
MemRef.IndexRegNum, MemRef.DispImm, MemRef.DispExpr,
MemRef.SegRegNum, MIB.getX86R11(), 8);
BB2.addInstruction(LoadCalleeAddrs);
MCInst StoreToStack;
MIB.createSaveToStack(StoreToStack, MIB.getStackPointer(), 8,
MIB.getX86R11(), 8);
BB2.addInstruction(StoreToStack);
MCInst PopR11;
MIB.createPopRegister(PopR11, MIB.getX86R11(), 8);
BB2.addInstruction(PopR11);
}
} else if (BrInfo.isReg()) {
MCInst StoreToStack;
MIB.createSaveToStack(StoreToStack, MIB.getStackPointer(), 0,
BrInfo.BranchReg, 8);
BB2.addInstruction(StoreToStack);
} else {
llvm_unreachable("not expected");
}
// return
MCInst Return;
MIB.createReturn(Return);
BB2.addInstruction(Return);
NewRetpoline->insertBasicBlocks(nullptr, std::move(NewBlocks),
/* UpdateLayout */ true,
/* UpdateCFIState */ false);
NewRetpoline->updateState(BinaryFunction::State::CFG_Finalized);
return NewRetpoline;
}
std::string createRetpolineFunctionTag(BinaryContext &BC,
const IndirectBranchInfo &BrInfo,
bool R11Available) {
std::string Tag;
llvm::raw_string_ostream TagOS(Tag);
TagOS << "__retpoline_";
if (BrInfo.isReg()) {
BC.InstPrinter->printRegName(TagOS, BrInfo.BranchReg);
TagOS << "_";
TagOS.flush();
return Tag;
}
// Memory Branch
if (R11Available)
return "__retpoline_r11";
const IndirectBranchInfo::MemOpInfo &MemRef = BrInfo.Memory;
TagOS << "mem_";
if (MemRef.BaseRegNum != BC.MIB->getNoRegister())
BC.InstPrinter->printRegName(TagOS, MemRef.BaseRegNum);
TagOS << "+";
if (MemRef.DispExpr)
MemRef.DispExpr->print(TagOS, BC.AsmInfo.get());
else
TagOS << MemRef.DispImm;
if (MemRef.IndexRegNum != BC.MIB->getNoRegister()) {
TagOS << "+" << MemRef.ScaleImm << "*";
BC.InstPrinter->printRegName(TagOS, MemRef.IndexRegNum);
}
if (MemRef.SegRegNum != BC.MIB->getNoRegister()) {
TagOS << "_seg_";
BC.InstPrinter->printRegName(TagOS, MemRef.SegRegNum);
}
TagOS.flush();
return Tag;
}
BinaryFunction *RetpolineInsertion::getOrCreateRetpoline(
BinaryContext &BC, const IndirectBranchInfo &BrInfo, bool R11Available) {
const std::string RetpolineTag =
createRetpolineFunctionTag(BC, BrInfo, R11Available);
if (CreatedRetpolines.count(RetpolineTag))
return CreatedRetpolines[RetpolineTag];
return CreatedRetpolines[RetpolineTag] =
createNewRetpoline(BC, RetpolineTag, BrInfo, R11Available);
}
void createBranchReplacement(BinaryContext &BC,
const IndirectBranchInfo &BrInfo,
bool R11Available,
InstructionListType &Replacement,
const MCSymbol *RetpolineSymbol) {
auto &MIB = *BC.MIB;
// Load the branch address in r11 if available
if (BrInfo.isMem() && R11Available) {
const IndirectBranchInfo::MemOpInfo &MemRef = BrInfo.Memory;
MCInst LoadCalleeAddrs;
MIB.createLoad(LoadCalleeAddrs, MemRef.BaseRegNum, MemRef.ScaleImm,
MemRef.IndexRegNum, MemRef.DispImm, MemRef.DispExpr,
MemRef.SegRegNum, MIB.getX86R11(), 8);
Replacement.push_back(LoadCalleeAddrs);
}
// Call the retpoline
MCInst RetpolineCall;
MIB.createDirectCall(RetpolineCall, RetpolineSymbol, BC.Ctx.get(),
BrInfo.isJump() || BrInfo.isTailCall());
Replacement.push_back(RetpolineCall);
}
IndirectBranchInfo::IndirectBranchInfo(MCInst &Inst, MCPlusBuilder &MIB) {
IsCall = MIB.isCall(Inst);
IsTailCall = MIB.isTailCall(Inst);
if (MIB.isBranchOnMem(Inst)) {
IsMem = true;
std::optional<MCPlusBuilder::X86MemOperand> MO =
MIB.evaluateX86MemoryOperand(Inst);
if (!MO)
llvm_unreachable("not expected");
Memory = MO.value();
} else if (MIB.isBranchOnReg(Inst)) {
assert(MCPlus::getNumPrimeOperands(Inst) == 1 && "expect 1 operand");
BranchReg = Inst.getOperand(0).getReg();
} else {
llvm_unreachable("unexpected instruction");
}
}
void RetpolineInsertion::runOnFunctions(BinaryContext &BC) {
if (!opts::InsertRetpolines)
return;
assert(BC.isX86() &&
"retpoline insertion not supported for target architecture");
assert(BC.HasRelocations && "retpoline mode not supported in non-reloc");
auto &MIB = *BC.MIB;
uint32_t RetpolinedBranches = 0;
for (auto &It : BC.getBinaryFunctions()) {
BinaryFunction &Function = It.second;
for (BinaryBasicBlock &BB : Function) {
for (auto It = BB.begin(); It != BB.end(); ++It) {
MCInst &Inst = *It;
if (!MIB.isIndirectCall(Inst) && !MIB.isIndirectBranch(Inst))
continue;
IndirectBranchInfo BrInfo(Inst, MIB);
bool R11Available = false;
BinaryFunction *TargetRetpoline;
InstructionListType Replacement;
// Determine if r11 is available before this instruction
if (BrInfo.isMem()) {
if (MIB.hasAnnotation(Inst, "PLTCall"))
R11Available = true;
else if (opts::R11Availability == AvailabilityOptions::ALWAYS)
R11Available = true;
else if (opts::R11Availability == AvailabilityOptions::ABI)
R11Available = BrInfo.isCall();
}
// If the instruction addressing pattern uses rsp and the retpoline
// loads the callee address then displacement needs to be updated
if (BrInfo.isMem() && !R11Available) {
IndirectBranchInfo::MemOpInfo &MemRef = BrInfo.Memory;
int Addend = (BrInfo.isJump() || BrInfo.isTailCall()) ? 8 : 16;
if (MemRef.BaseRegNum == MIB.getStackPointer())
MemRef.DispImm += Addend;
if (MemRef.IndexRegNum == MIB.getStackPointer())
MemRef.DispImm += Addend * MemRef.ScaleImm;
}
TargetRetpoline = getOrCreateRetpoline(BC, BrInfo, R11Available);
createBranchReplacement(BC, BrInfo, R11Available, Replacement,
TargetRetpoline->getSymbol());
It = BB.replaceInstruction(It, Replacement.begin(), Replacement.end());
RetpolinedBranches++;
}
}
}
outs() << "BOLT-INFO: The number of created retpoline functions is : "
<< CreatedRetpolines.size()
<< "\nBOLT-INFO: The number of retpolined branches is : "
<< RetpolinedBranches << "\n";
}
} // namespace bolt
} // namespace llvm