LLVM 22.0.0git
AArch64PointerAuth.cpp
Go to the documentation of this file.
1//===-- AArch64PointerAuth.cpp -- Harden code using PAuth ------------------==//
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
10
11#include "AArch64.h"
12#include "AArch64InstrInfo.h"
14#include "AArch64Subtarget.h"
19
20using namespace llvm;
21using namespace llvm::AArch64PAuth;
22
23#define AARCH64_POINTER_AUTH_NAME "AArch64 Pointer Authentication"
24
25namespace {
26
27class AArch64PointerAuth : public MachineFunctionPass {
28public:
29 static char ID;
30
31 AArch64PointerAuth() : MachineFunctionPass(ID) {}
32
33 bool runOnMachineFunction(MachineFunction &MF) override;
34
35 StringRef getPassName() const override { return AARCH64_POINTER_AUTH_NAME; }
36
37private:
38 const AArch64Subtarget *Subtarget = nullptr;
39 const AArch64InstrInfo *TII = nullptr;
40
41 void signLR(MachineFunction &MF, MachineBasicBlock::iterator MBBI) const;
42
43 void authenticateLR(MachineFunction &MF,
45
46 bool checkAuthenticatedLR(MachineBasicBlock::iterator TI) const;
47};
48
49} // end anonymous namespace
50
51INITIALIZE_PASS(AArch64PointerAuth, "aarch64-ptrauth",
52 AARCH64_POINTER_AUTH_NAME, false, false)
53
55 return new AArch64PointerAuth();
56}
57
58char AArch64PointerAuth::ID = 0;
59
63 MCSymbol *PACSym) {
64 BuildMI(MBB, I, DL, TII.get(AArch64::ADRP), AArch64::X16)
65 .addSym(PACSym, AArch64II::MO_PAGE);
66 BuildMI(MBB, I, DL, TII.get(AArch64::ADDXri), AArch64::X16)
67 .addReg(AArch64::X16)
69 .addImm(0);
70}
71
72// Where PAuthLR support is not known at compile time, it is supported using
73// PACM. PACM is in the hint space so has no effect when PAuthLR is not
74// supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
75// and RETAA/RETAB if the hardware supports PAuthLR.
76static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
78 MachineInstr::MIFlag Flags, MCSymbol *PACSym = nullptr) {
79 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
80 auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
81
82 // Offset to PAC*SP using ADRP + ADD.
83 if (PACSym) {
86 }
87
88 // Only emit PACM if -mbranch-protection has +pc and the target does not
89 // have feature +pauth-lr.
90 if (MFnI.branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
91 BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
92}
93
95 MachineInstr::MIFlag Flags, bool EmitCFI) {
96 if (!EmitCFI)
97 return;
98
99 auto &MF = *MBB.getParent();
100 auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
101
102 CFIInstBuilder CFIBuilder(MBB, MBBI, Flags);
103 MFnI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
104 : CFIBuilder.buildNegateRAState();
105}
106
107void AArch64PointerAuth::signLR(MachineFunction &MF,
109 auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
110 bool UseBKey = MFnI.shouldSignWithBKey();
111 bool EmitCFI = MFnI.needsDwarfUnwindInfo(MF);
112 bool NeedsWinCFI = MF.hasWinCFI();
113
115
116 // Debug location must be unknown, see AArch64FrameLowering::emitPrologue.
117 DebugLoc DL;
118
119 if (UseBKey) {
120 BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
122 }
123
124 // PAuthLR authentication instructions need to know the value of PC at the
125 // point of signing (PACI*).
126 if (MFnI.branchProtectionPAuthLR()) {
127 MCSymbol *PACSym = MF.getContext().createTempSymbol();
128 MFnI.setSigningInstrLabel(PACSym);
129 }
130
131 // No SEH opcode for this one; it doesn't materialize into an
132 // instruction on Windows.
133 if (MFnI.branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
135 BuildMI(MBB, MBBI, DL,
136 TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSPPC
137 : AArch64::PACIASPPC))
139 ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
140 } else {
142 if (MFnI.branchProtectionPAuthLR())
144 BuildMI(MBB, MBBI, DL,
145 TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSP
146 : AArch64::PACIASP))
148 ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
149 if (!MFnI.branchProtectionPAuthLR())
151 }
152
153 if (!EmitCFI && NeedsWinCFI) {
154 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
156 }
157}
158
159void AArch64PointerAuth::authenticateLR(
162 bool UseBKey = MFnI->shouldSignWithBKey();
163 bool EmitAsyncCFI = MFnI->needsAsyncDwarfUnwindInfo(MF);
164 bool NeedsWinCFI = MF.hasWinCFI();
165
167 DebugLoc DL = MBBI->getDebugLoc();
168 // MBBI points to a PAUTH_EPILOGUE instruction to be replaced and
169 // TI points to a terminator instruction that may or may not be combined.
170 // Note that inserting new instructions "before MBBI" and "before TI" is
171 // not the same because if ShadowCallStack is enabled, its instructions
172 // are placed between MBBI and TI.
174
175 // The AUTIASP instruction assembles to a hint instruction before v8.3a so
176 // this instruction can safely used for any v8a architecture.
177 // From v8.3a onwards there are optimised authenticate LR and return
178 // instructions, namely RETA{A,B}, that can be used instead. In this case the
179 // DW_CFA_AARCH64_negate_ra_state can't be emitted.
180 bool TerminatorIsCombinable =
181 TI != MBB.end() && TI->getOpcode() == AArch64::RET;
182 MCSymbol *PACSym = MFnI->getSigningInstrLabel();
183
184 if (Subtarget->hasPAuth() && TerminatorIsCombinable && !NeedsWinCFI &&
185 !MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) {
186 if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
187 assert(PACSym && "No PAC instruction to refer to");
189 BuildMI(MBB, TI, DL,
190 TII->get(UseBKey ? AArch64::RETABSPPCi : AArch64::RETAASPPCi))
191 .addSym(PACSym)
194 } else {
195 BuildPACM(*Subtarget, MBB, TI, DL, MachineInstr::FrameDestroy, PACSym);
196 BuildMI(MBB, TI, DL, TII->get(UseBKey ? AArch64::RETAB : AArch64::RETAA))
199 }
200 MBB.erase(TI);
201 } else {
202 if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
203 assert(PACSym && "No PAC instruction to refer to");
206 BuildMI(MBB, MBBI, DL,
207 TII->get(UseBKey ? AArch64::AUTIBSPPCi : AArch64::AUTIASPPCi))
208 .addSym(PACSym)
210 } else {
211 BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameDestroy, PACSym);
212 if (MFnI->branchProtectionPAuthLR())
214 BuildMI(MBB, MBBI, DL,
215 TII->get(UseBKey ? AArch64::AUTIBSP : AArch64::AUTIASP))
217 if (!MFnI->branchProtectionPAuthLR())
219 }
220
221 if (NeedsWinCFI) {
222 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
224 }
225 }
226}
227
229 switch (Method) {
230 case AuthCheckMethod::None:
231 return 0;
232 case AuthCheckMethod::DummyLoad:
233 return 4;
234 case AuthCheckMethod::HighBitsNoTBI:
235 return 12;
236 case AuthCheckMethod::XPACHint:
237 case AuthCheckMethod::XPAC:
238 return 20;
239 }
240 llvm_unreachable("Unknown AuthCheckMethod enum");
241}
242
243bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) {
244 Subtarget = &MF.getSubtarget<AArch64Subtarget>();
245 TII = Subtarget->getInstrInfo();
246
248
249 bool Modified = false;
250
251 for (auto &MBB : MF) {
252 for (auto &MI : MBB) {
253 switch (MI.getOpcode()) {
254 default:
255 break;
256 case AArch64::PAUTH_PROLOGUE:
257 case AArch64::PAUTH_EPILOGUE:
258 PAuthPseudoInstrs.push_back(MI.getIterator());
259 break;
260 }
261 }
262 }
263
264 for (auto It : PAuthPseudoInstrs) {
265 switch (It->getOpcode()) {
266 case AArch64::PAUTH_PROLOGUE:
267 signLR(MF, It);
268 break;
269 case AArch64::PAUTH_EPILOGUE:
270 authenticateLR(MF, It);
271 break;
272 default:
273 llvm_unreachable("Unhandled opcode");
274 }
275 It->eraseFromParent();
276 Modified = true;
277 }
278
279 return Modified;
280}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define AARCH64_POINTER_AUTH_NAME
static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, MachineInstr::MIFlag Flags, MCSymbol *PACSym=nullptr)
static void emitPACCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineInstr::MIFlag Flags, bool EmitCFI)
static void emitPACSymOffsetIntoX16(const TargetInstrInfo &TII, MachineBasicBlock &MBB, MachineBasicBlock::iterator I, DebugLoc DL, MCSymbol *PACSym)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:56
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
const AArch64InstrInfo * getInstrInfo() const override
Helper class for creating CFI instructions and inserting them into MIR.
A debug info location.
Definition: DebugLoc.h:124
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:314
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.cpp:727
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:386
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:42
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
LLVM_ABI instr_iterator getFirstInstrTerminator()
Same getFirstTerminator but it ignores bundles and return an instr_iterator instead.
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.
MCContext & getContext() const
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & copyImplicitOps(const MachineInstr &OtherMI) const
Copy all the implicit operands from OtherMI onto this one.
LLVM_ABI void setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol)
Set a symbol that will be emitted just prior to the instruction itself.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
TargetInstrInfo - Interface to description of machine instruction set.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
unsigned getCheckerSizeInBytes(AuthCheckMethod Method)
Returns the number of bytes added by checkAuthenticatedRegister.
AuthCheckMethod
Variants of check performed on an authenticated pointer.
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
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createAArch64PointerAuthPass()