LLVM 22.0.0git
X86IndirectBranchTracking.cpp
Go to the documentation of this file.
1//===---- X86IndirectBranchTracking.cpp - Enables CET IBT mechanism -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a pass that enables Indirect Branch Tracking (IBT) as part
10// of Control-Flow Enforcement Technology (CET).
11// The pass adds ENDBR (End Branch) machine instructions at the beginning of
12// each basic block or function that is referenced by an indrect jump/call
13// instruction.
14// The ENDBR instructions have a NOP encoding and as such are ignored in
15// targets that do not support CET IBT mechanism.
16//===----------------------------------------------------------------------===//
17
18#include "X86.h"
19#include "X86InstrInfo.h"
20#include "X86Subtarget.h"
21#include "X86TargetMachine.h"
22#include "llvm/ADT/Statistic.h"
26#include "llvm/IR/Module.h"
27
28using namespace llvm;
29
30#define DEBUG_TYPE "x86-indirect-branch-tracking"
31
33 "x86-indirect-branch-tracking", cl::init(false), cl::Hidden,
34 cl::desc("Enable X86 indirect branch tracking pass."));
35
36STATISTIC(NumEndBranchAdded, "Number of ENDBR instructions added");
37
38namespace {
39class X86IndirectBranchTrackingPass : public MachineFunctionPass {
40public:
41 X86IndirectBranchTrackingPass() : MachineFunctionPass(ID) {}
42
43 StringRef getPassName() const override {
44 return "X86 Indirect Branch Tracking";
45 }
46
47 bool runOnMachineFunction(MachineFunction &MF) override;
48
49private:
50 static char ID;
51
52 /// Machine instruction info used throughout the class.
53 const X86InstrInfo *TII = nullptr;
54
55 /// Endbr opcode for the current machine function.
56 unsigned int EndbrOpcode = 0;
57
58 /// Adds a new ENDBR instruction to the beginning of the MBB.
59 /// The function will not add it if already exists.
60 /// It will add ENDBR32 or ENDBR64 opcode, depending on the target.
61 /// \returns true if the ENDBR was added and false otherwise.
62 bool addENDBR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;
63};
64
65} // end anonymous namespace
66
67char X86IndirectBranchTrackingPass::ID = 0;
68
70 return new X86IndirectBranchTrackingPass();
71}
72
73bool X86IndirectBranchTrackingPass::addENDBR(
75 assert(TII && "Target instruction info was not initialized");
76 assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) &&
77 "Unexpected Endbr opcode");
78
79 // If the MBB/I is empty or the current instruction is not ENDBR,
80 // insert ENDBR instruction to the location of I.
81 if (I == MBB.end() || I->getOpcode() != EndbrOpcode) {
82 BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(EndbrOpcode));
83 ++NumEndBranchAdded;
84 return true;
85 }
86 return false;
87}
88
90 if (!MOp.isGlobal())
91 return false;
92 auto *CalleeFn = dyn_cast<Function>(MOp.getGlobal());
93 if (!CalleeFn)
94 return false;
95 AttributeList Attrs = CalleeFn->getAttributes();
96 return Attrs.hasFnAttr(Attribute::ReturnsTwice);
97}
98
99// Checks if function should have an ENDBR in its prologue
100static bool needsPrologueENDBR(MachineFunction &MF, const Module *M) {
101 Function &F = MF.getFunction();
102
103 if (F.doesNoCfCheck())
104 return false;
105
106 switch (MF.getTarget().getCodeModel()) {
107 // Large code model functions always reachable through indirect calls.
108 case CodeModel::Large:
109 return true;
110 // Address taken or externally linked functions may be reachable.
111 default:
112 return (F.hasAddressTaken() || !F.hasLocalLinkage());
113 }
114}
115
116bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) {
117 const X86Subtarget &SubTarget = MF.getSubtarget<X86Subtarget>();
118
119 const Module *M = MF.getFunction().getParent();
120 // Check that the cf-protection-branch is enabled.
121 Metadata *isCFProtectionSupported = M->getModuleFlag("cf-protection-branch");
122
123 // NB: We need to enable IBT in jitted code if JIT compiler is CET
124 // enabled.
125 const X86TargetMachine *TM =
126 static_cast<const X86TargetMachine *>(&MF.getTarget());
127#ifdef __CET__
128 bool isJITwithCET = TM->isJIT();
129#else
130 bool isJITwithCET = false;
131#endif
132 if (!isCFProtectionSupported && !IndirectBranchTracking && !isJITwithCET)
133 return false;
134
135 // True if the current MF was changed and false otherwise.
136 bool Changed = false;
137
138 TII = SubTarget.getInstrInfo();
139 EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32;
140
141 // If function is reachable indirectly, mark the first BB with ENDBR.
142 if (needsPrologueENDBR(MF, M)) {
143 auto MBB = MF.begin();
144 Changed |= addENDBR(*MBB, MBB->begin());
145 }
146
147 for (auto &MBB : MF) {
148 // Find all basic blocks that their address was taken (for example
149 // in the case of indirect jump) and add ENDBR instruction.
151 Changed |= addENDBR(MBB, MBB.begin());
152
153 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
154 if (I->isCall() && I->getNumOperands() > 0 &&
155 IsCallReturnTwice(I->getOperand(0))) {
156 Changed |= addENDBR(MBB, std::next(I));
157 }
158 }
159
160 // Exception handle may indirectly jump to catch pad, So we should add
161 // ENDBR before catch pad instructions. For SjLj exception model, it will
162 // create a new BB(new landingpad) indirectly jump to the old landingpad.
163 if (TM->Options.ExceptionModel == ExceptionHandling::SjLj) {
164 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
165 // New Landingpad BB without EHLabel.
166 if (MBB.isEHPad()) {
167 if (I->isDebugInstr())
168 continue;
169 Changed |= addENDBR(MBB, I);
170 break;
171 } else if (I->isEHLabel()) {
172 // Old Landingpad BB (is not Landingpad now) with
173 // the old "callee" EHLabel.
174 MCSymbol *Sym = I->getOperand(0).getMCSymbol();
175 if (!MF.hasCallSiteLandingPad(Sym))
176 continue;
177 Changed |= addENDBR(MBB, std::next(I));
178 break;
179 }
180 }
181 } else if (MBB.isEHPad()){
182 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
183 if (!I->isEHLabel())
184 continue;
185 Changed |= addENDBR(MBB, std::next(I));
186 break;
187 }
188 }
189 }
190 return Changed;
191}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
dxil translate DXIL Translate Metadata
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
Machine Check Debug Module
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:167
static bool needsPrologueENDBR(MachineFunction &MF, const Module *M)
static bool IsCallReturnTwice(llvm::MachineOperand &MOp)
cl::opt< bool > IndirectBranchTracking("x86-indirect-branch-tracking", cl::init(false), cl::Hidden, cl::desc("Enable X86 indirect branch tracking pass."))
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
Module * getParent()
Get the module that this global value is contained inside of...
bool isEHPad() const
Returns true if the block is a landing pad.
bool isIRBlockAddressTaken() const
Test whether this block is the target of an IR BlockAddress.
bool isMachineBlockAddressTaken() const
Test whether this block is used as something other than the target of a terminator,...
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
CodeModel::Model getCodeModel() const
Returns the code model.
const X86InstrInfo * getInstrInfo() const override
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
FunctionPass * createX86IndirectBranchTrackingPass()
This pass inserts ENDBR instructions before indirect jump/call destinations as part of CET IBT mechan...