LLVM 17.0.0git
AArch64KCFI.cpp
Go to the documentation of this file.
1//===---- AArch64KCFI.cpp - Implements KCFI -------------------------------===//
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 implements KCFI indirect call checking.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AArch64.h"
14#include "AArch64InstrInfo.h"
15#include "AArch64Subtarget.h"
17#include "llvm/ADT/Statistic.h"
22
23using namespace llvm;
24
25#define DEBUG_TYPE "aarch64-kcfi"
26#define AARCH64_KCFI_PASS_NAME "Insert KCFI indirect call checks"
27
28STATISTIC(NumKCFIChecksAdded, "Number of indirect call checks added");
29
30namespace {
31class AArch64KCFI : public MachineFunctionPass {
32public:
33 static char ID;
34
35 AArch64KCFI() : MachineFunctionPass(ID) {}
36
37 StringRef getPassName() const override { return AARCH64_KCFI_PASS_NAME; }
38 bool runOnMachineFunction(MachineFunction &MF) override;
39
40private:
41 /// Machine instruction info used throughout the class.
42 const AArch64InstrInfo *TII = nullptr;
43
44 /// Emits a KCFI check before an indirect call.
45 /// \returns true if the check was added and false otherwise.
46 bool emitCheck(MachineBasicBlock &MBB,
48};
49
50char AArch64KCFI::ID = 0;
51} // end anonymous namespace
52
53INITIALIZE_PASS(AArch64KCFI, DEBUG_TYPE, AARCH64_KCFI_PASS_NAME, false, false)
54
55FunctionPass *llvm::createAArch64KCFIPass() { return new AArch64KCFI(); }
56
57bool AArch64KCFI::emitCheck(MachineBasicBlock &MBB,
59 assert(TII && "Target instruction info was not initialized");
60
61 // If the call instruction is bundled, we can only emit a check safely if
62 // it's the first instruction in the bundle.
63 if (MBBI->isBundled() && !std::prev(MBBI)->isBundle())
64 report_fatal_error("Cannot emit a KCFI check for a bundled call");
65
66 switch (MBBI->getOpcode()) {
67 case AArch64::BLR:
68 case AArch64::BLRNoIP:
69 case AArch64::TCRETURNri:
70 case AArch64::TCRETURNriBTI:
71 break;
72 default:
73 llvm_unreachable("Unexpected CFI call opcode");
74 }
75
76 MachineOperand &Target = MBBI->getOperand(0);
77 assert(Target.isReg() && "Invalid target operand for an indirect call");
78 Target.setIsRenamable(false);
79
81 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(AArch64::KCFI_CHECK))
82 .addReg(Target.getReg())
83 .addImm(MBBI->getCFIType())
84 .getInstr();
85 MBBI->setCFIType(*MBB.getParent(), 0);
86
87 // If not already bundled, bundle the check and the call to prevent
88 // further changes.
89 if (!MBBI->isBundled())
90 finalizeBundle(MBB, Check->getIterator(), std::next(MBBI->getIterator()));
91
92 ++NumKCFIChecksAdded;
93 return true;
94}
95
96bool AArch64KCFI::runOnMachineFunction(MachineFunction &MF) {
97 const Module *M = MF.getMMI().getModule();
98 if (!M->getModuleFlag("kcfi"))
99 return false;
100
101 const auto &SubTarget = MF.getSubtarget<AArch64Subtarget>();
102 TII = SubTarget.getInstrInfo();
103
104 bool Changed = false;
105 for (MachineBasicBlock &MBB : MF) {
107 MIE = MBB.instr_end();
108 MII != MIE; ++MII) {
109 if (MII->isCall() && MII->getCFIType())
110 Changed |= emitCheck(MBB, MII);
111 }
112 }
113
114 return Changed;
115}
#define AARCH64_KCFI_PASS_NAME
Definition: AArch64KCFI.cpp:26
#define DEBUG_TYPE
Definition: AArch64KCFI.cpp:25
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator MBBI
const HexagonInstrInfo * TII
#define Check(C,...)
Definition: Lint.cpp:170
#define I(x, y, z)
Definition: MD5.cpp:58
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
instr_iterator instr_begin()
instr_iterator instr_end()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineModuleInfo & getMMI() const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
Definition: MachineInstr.h:68
const Module * getModule() const
MachineOperand class - Representation of each machine instruction operand.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target - Wrapper for Target specific information.
Iterator for intrusive lists based on ilist_node.
self_iterator getIterator()
Definition: ilist_node.h:82
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void finalizeBundle(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator FirstMI, MachineBasicBlock::instr_iterator LastMI)
finalizeBundle - Finalize a machine instruction bundle which includes a sequence of instructions star...
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
FunctionPass * createAArch64KCFIPass()
Definition: AArch64KCFI.cpp:55