1*5f757f3fSDimitry Andric //===-- AArch64PointerAuth.cpp -- Harden code using PAuth ------------------==// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric 9*5f757f3fSDimitry Andric #include "AArch64PointerAuth.h" 10*5f757f3fSDimitry Andric 11*5f757f3fSDimitry Andric #include "AArch64.h" 12*5f757f3fSDimitry Andric #include "AArch64InstrInfo.h" 13*5f757f3fSDimitry Andric #include "AArch64MachineFunctionInfo.h" 14*5f757f3fSDimitry Andric #include "AArch64Subtarget.h" 15*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 16*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 17*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 18*5f757f3fSDimitry Andric 19*5f757f3fSDimitry Andric using namespace llvm; 20*5f757f3fSDimitry Andric using namespace llvm::AArch64PAuth; 21*5f757f3fSDimitry Andric 22*5f757f3fSDimitry Andric #define AARCH64_POINTER_AUTH_NAME "AArch64 Pointer Authentication" 23*5f757f3fSDimitry Andric 24*5f757f3fSDimitry Andric namespace { 25*5f757f3fSDimitry Andric 26*5f757f3fSDimitry Andric class AArch64PointerAuth : public MachineFunctionPass { 27*5f757f3fSDimitry Andric public: 28*5f757f3fSDimitry Andric static char ID; 29*5f757f3fSDimitry Andric 30*5f757f3fSDimitry Andric AArch64PointerAuth() : MachineFunctionPass(ID) {} 31*5f757f3fSDimitry Andric 32*5f757f3fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 33*5f757f3fSDimitry Andric 34*5f757f3fSDimitry Andric StringRef getPassName() const override { return AARCH64_POINTER_AUTH_NAME; } 35*5f757f3fSDimitry Andric 36*5f757f3fSDimitry Andric private: 37*5f757f3fSDimitry Andric /// An immediate operand passed to BRK instruction, if it is ever emitted. 38*5f757f3fSDimitry Andric const unsigned BrkOperand = 0xc471; 39*5f757f3fSDimitry Andric 40*5f757f3fSDimitry Andric const AArch64Subtarget *Subtarget = nullptr; 41*5f757f3fSDimitry Andric const AArch64InstrInfo *TII = nullptr; 42*5f757f3fSDimitry Andric const AArch64RegisterInfo *TRI = nullptr; 43*5f757f3fSDimitry Andric 44*5f757f3fSDimitry Andric void signLR(MachineFunction &MF, MachineBasicBlock::iterator MBBI) const; 45*5f757f3fSDimitry Andric 46*5f757f3fSDimitry Andric void authenticateLR(MachineFunction &MF, 47*5f757f3fSDimitry Andric MachineBasicBlock::iterator MBBI) const; 48*5f757f3fSDimitry Andric 49*5f757f3fSDimitry Andric bool checkAuthenticatedLR(MachineBasicBlock::iterator TI) const; 50*5f757f3fSDimitry Andric }; 51*5f757f3fSDimitry Andric 52*5f757f3fSDimitry Andric } // end anonymous namespace 53*5f757f3fSDimitry Andric 54*5f757f3fSDimitry Andric INITIALIZE_PASS(AArch64PointerAuth, "aarch64-ptrauth", 55*5f757f3fSDimitry Andric AARCH64_POINTER_AUTH_NAME, false, false) 56*5f757f3fSDimitry Andric 57*5f757f3fSDimitry Andric FunctionPass *llvm::createAArch64PointerAuthPass() { 58*5f757f3fSDimitry Andric return new AArch64PointerAuth(); 59*5f757f3fSDimitry Andric } 60*5f757f3fSDimitry Andric 61*5f757f3fSDimitry Andric char AArch64PointerAuth::ID = 0; 62*5f757f3fSDimitry Andric 63*5f757f3fSDimitry Andric void AArch64PointerAuth::signLR(MachineFunction &MF, 64*5f757f3fSDimitry Andric MachineBasicBlock::iterator MBBI) const { 65*5f757f3fSDimitry Andric const AArch64FunctionInfo *MFnI = MF.getInfo<AArch64FunctionInfo>(); 66*5f757f3fSDimitry Andric bool UseBKey = MFnI->shouldSignWithBKey(); 67*5f757f3fSDimitry Andric bool EmitCFI = MFnI->needsDwarfUnwindInfo(MF); 68*5f757f3fSDimitry Andric bool NeedsWinCFI = MF.hasWinCFI(); 69*5f757f3fSDimitry Andric 70*5f757f3fSDimitry Andric MachineBasicBlock &MBB = *MBBI->getParent(); 71*5f757f3fSDimitry Andric 72*5f757f3fSDimitry Andric // Debug location must be unknown, see AArch64FrameLowering::emitPrologue. 73*5f757f3fSDimitry Andric DebugLoc DL; 74*5f757f3fSDimitry Andric 75*5f757f3fSDimitry Andric if (UseBKey) { 76*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) 77*5f757f3fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 78*5f757f3fSDimitry Andric } 79*5f757f3fSDimitry Andric 80*5f757f3fSDimitry Andric // No SEH opcode for this one; it doesn't materialize into an 81*5f757f3fSDimitry Andric // instruction on Windows. 82*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, 83*5f757f3fSDimitry Andric TII->get(UseBKey ? AArch64::PACIBSP : AArch64::PACIASP)) 84*5f757f3fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric if (EmitCFI) { 87*5f757f3fSDimitry Andric unsigned CFIIndex = 88*5f757f3fSDimitry Andric MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr)); 89*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 90*5f757f3fSDimitry Andric .addCFIIndex(CFIIndex) 91*5f757f3fSDimitry Andric .setMIFlags(MachineInstr::FrameSetup); 92*5f757f3fSDimitry Andric } else if (NeedsWinCFI) { 93*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR)) 94*5f757f3fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 95*5f757f3fSDimitry Andric } 96*5f757f3fSDimitry Andric } 97*5f757f3fSDimitry Andric 98*5f757f3fSDimitry Andric void AArch64PointerAuth::authenticateLR( 99*5f757f3fSDimitry Andric MachineFunction &MF, MachineBasicBlock::iterator MBBI) const { 100*5f757f3fSDimitry Andric const AArch64FunctionInfo *MFnI = MF.getInfo<AArch64FunctionInfo>(); 101*5f757f3fSDimitry Andric bool UseBKey = MFnI->shouldSignWithBKey(); 102*5f757f3fSDimitry Andric bool EmitAsyncCFI = MFnI->needsAsyncDwarfUnwindInfo(MF); 103*5f757f3fSDimitry Andric bool NeedsWinCFI = MF.hasWinCFI(); 104*5f757f3fSDimitry Andric 105*5f757f3fSDimitry Andric MachineBasicBlock &MBB = *MBBI->getParent(); 106*5f757f3fSDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 107*5f757f3fSDimitry Andric // MBBI points to a PAUTH_EPILOGUE instruction to be replaced and 108*5f757f3fSDimitry Andric // TI points to a terminator instruction that may or may not be combined. 109*5f757f3fSDimitry Andric // Note that inserting new instructions "before MBBI" and "before TI" is 110*5f757f3fSDimitry Andric // not the same because if ShadowCallStack is enabled, its instructions 111*5f757f3fSDimitry Andric // are placed between MBBI and TI. 112*5f757f3fSDimitry Andric MachineBasicBlock::iterator TI = MBB.getFirstInstrTerminator(); 113*5f757f3fSDimitry Andric 114*5f757f3fSDimitry Andric // The AUTIASP instruction assembles to a hint instruction before v8.3a so 115*5f757f3fSDimitry Andric // this instruction can safely used for any v8a architecture. 116*5f757f3fSDimitry Andric // From v8.3a onwards there are optimised authenticate LR and return 117*5f757f3fSDimitry Andric // instructions, namely RETA{A,B}, that can be used instead. In this case the 118*5f757f3fSDimitry Andric // DW_CFA_AARCH64_negate_ra_state can't be emitted. 119*5f757f3fSDimitry Andric bool TerminatorIsCombinable = 120*5f757f3fSDimitry Andric TI != MBB.end() && TI->getOpcode() == AArch64::RET; 121*5f757f3fSDimitry Andric if (Subtarget->hasPAuth() && TerminatorIsCombinable && !NeedsWinCFI && 122*5f757f3fSDimitry Andric !MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) { 123*5f757f3fSDimitry Andric unsigned CombinedRetOpcode = UseBKey ? AArch64::RETAB : AArch64::RETAA; 124*5f757f3fSDimitry Andric BuildMI(MBB, TI, DL, TII->get(CombinedRetOpcode)).copyImplicitOps(*TI); 125*5f757f3fSDimitry Andric MBB.erase(TI); 126*5f757f3fSDimitry Andric } else { 127*5f757f3fSDimitry Andric unsigned AutOpcode = UseBKey ? AArch64::AUTIBSP : AArch64::AUTIASP; 128*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(AutOpcode)) 129*5f757f3fSDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 130*5f757f3fSDimitry Andric 131*5f757f3fSDimitry Andric if (EmitAsyncCFI) { 132*5f757f3fSDimitry Andric unsigned CFIIndex = 133*5f757f3fSDimitry Andric MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr)); 134*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 135*5f757f3fSDimitry Andric .addCFIIndex(CFIIndex) 136*5f757f3fSDimitry Andric .setMIFlags(MachineInstr::FrameDestroy); 137*5f757f3fSDimitry Andric } 138*5f757f3fSDimitry Andric if (NeedsWinCFI) { 139*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR)) 140*5f757f3fSDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 141*5f757f3fSDimitry Andric } 142*5f757f3fSDimitry Andric } 143*5f757f3fSDimitry Andric } 144*5f757f3fSDimitry Andric 145*5f757f3fSDimitry Andric namespace { 146*5f757f3fSDimitry Andric 147*5f757f3fSDimitry Andric // Mark dummy LDR instruction as volatile to prevent removing it as dead code. 148*5f757f3fSDimitry Andric MachineMemOperand *createCheckMemOperand(MachineFunction &MF, 149*5f757f3fSDimitry Andric const AArch64Subtarget &Subtarget) { 150*5f757f3fSDimitry Andric MachinePointerInfo PointerInfo(Subtarget.getAddressCheckPSV()); 151*5f757f3fSDimitry Andric auto MOVolatileLoad = 152*5f757f3fSDimitry Andric MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile; 153*5f757f3fSDimitry Andric 154*5f757f3fSDimitry Andric return MF.getMachineMemOperand(PointerInfo, MOVolatileLoad, 4, Align(4)); 155*5f757f3fSDimitry Andric } 156*5f757f3fSDimitry Andric 157*5f757f3fSDimitry Andric } // namespace 158*5f757f3fSDimitry Andric 159*5f757f3fSDimitry Andric MachineBasicBlock &llvm::AArch64PAuth::checkAuthenticatedRegister( 160*5f757f3fSDimitry Andric MachineBasicBlock::iterator MBBI, AuthCheckMethod Method, 161*5f757f3fSDimitry Andric Register AuthenticatedReg, Register TmpReg, bool UseIKey, unsigned BrkImm) { 162*5f757f3fSDimitry Andric 163*5f757f3fSDimitry Andric MachineBasicBlock &MBB = *MBBI->getParent(); 164*5f757f3fSDimitry Andric MachineFunction &MF = *MBB.getParent(); 165*5f757f3fSDimitry Andric const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>(); 166*5f757f3fSDimitry Andric const AArch64InstrInfo *TII = Subtarget.getInstrInfo(); 167*5f757f3fSDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 168*5f757f3fSDimitry Andric 169*5f757f3fSDimitry Andric // First, handle the methods not requiring creating extra MBBs. 170*5f757f3fSDimitry Andric switch (Method) { 171*5f757f3fSDimitry Andric default: 172*5f757f3fSDimitry Andric break; 173*5f757f3fSDimitry Andric case AuthCheckMethod::None: 174*5f757f3fSDimitry Andric return MBB; 175*5f757f3fSDimitry Andric case AuthCheckMethod::DummyLoad: 176*5f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRWui), getWRegFromXReg(TmpReg)) 177*5f757f3fSDimitry Andric .addReg(AArch64::LR) 178*5f757f3fSDimitry Andric .addImm(0) 179*5f757f3fSDimitry Andric .addMemOperand(createCheckMemOperand(MF, Subtarget)); 180*5f757f3fSDimitry Andric return MBB; 181*5f757f3fSDimitry Andric } 182*5f757f3fSDimitry Andric 183*5f757f3fSDimitry Andric // Control flow has to be changed, so arrange new MBBs. 184*5f757f3fSDimitry Andric 185*5f757f3fSDimitry Andric // At now, at least an AUT* instruction is expected before MBBI 186*5f757f3fSDimitry Andric assert(MBBI != MBB.begin() && 187*5f757f3fSDimitry Andric "Cannot insert the check at the very beginning of MBB"); 188*5f757f3fSDimitry Andric // The block to insert check into. 189*5f757f3fSDimitry Andric MachineBasicBlock *CheckBlock = &MBB; 190*5f757f3fSDimitry Andric // The remaining part of the original MBB that is executed on success. 191*5f757f3fSDimitry Andric MachineBasicBlock *SuccessBlock = MBB.splitAt(*std::prev(MBBI)); 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric // The block that explicitly generates a break-point exception on failure. 194*5f757f3fSDimitry Andric MachineBasicBlock *BreakBlock = 195*5f757f3fSDimitry Andric MF.CreateMachineBasicBlock(MBB.getBasicBlock()); 196*5f757f3fSDimitry Andric MF.push_back(BreakBlock); 197*5f757f3fSDimitry Andric MBB.splitSuccessor(SuccessBlock, BreakBlock); 198*5f757f3fSDimitry Andric 199*5f757f3fSDimitry Andric assert(CheckBlock->getFallThrough() == SuccessBlock); 200*5f757f3fSDimitry Andric BuildMI(BreakBlock, DL, TII->get(AArch64::BRK)).addImm(BrkImm); 201*5f757f3fSDimitry Andric 202*5f757f3fSDimitry Andric switch (Method) { 203*5f757f3fSDimitry Andric case AuthCheckMethod::None: 204*5f757f3fSDimitry Andric case AuthCheckMethod::DummyLoad: 205*5f757f3fSDimitry Andric llvm_unreachable("Should be handled above"); 206*5f757f3fSDimitry Andric case AuthCheckMethod::HighBitsNoTBI: 207*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::EORXrs), TmpReg) 208*5f757f3fSDimitry Andric .addReg(AuthenticatedReg) 209*5f757f3fSDimitry Andric .addReg(AuthenticatedReg) 210*5f757f3fSDimitry Andric .addImm(1); 211*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::TBNZX)) 212*5f757f3fSDimitry Andric .addReg(TmpReg) 213*5f757f3fSDimitry Andric .addImm(62) 214*5f757f3fSDimitry Andric .addMBB(BreakBlock); 215*5f757f3fSDimitry Andric return *SuccessBlock; 216*5f757f3fSDimitry Andric case AuthCheckMethod::XPACHint: 217*5f757f3fSDimitry Andric assert(AuthenticatedReg == AArch64::LR && 218*5f757f3fSDimitry Andric "XPACHint mode is only compatible with checking the LR register"); 219*5f757f3fSDimitry Andric assert(UseIKey && "XPACHint mode is only compatible with I-keys"); 220*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::ORRXrs), TmpReg) 221*5f757f3fSDimitry Andric .addReg(AArch64::XZR) 222*5f757f3fSDimitry Andric .addReg(AArch64::LR) 223*5f757f3fSDimitry Andric .addImm(0); 224*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::XPACLRI)); 225*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::SUBSXrs), AArch64::XZR) 226*5f757f3fSDimitry Andric .addReg(TmpReg) 227*5f757f3fSDimitry Andric .addReg(AArch64::LR) 228*5f757f3fSDimitry Andric .addImm(0); 229*5f757f3fSDimitry Andric BuildMI(CheckBlock, DL, TII->get(AArch64::Bcc)) 230*5f757f3fSDimitry Andric .addImm(AArch64CC::NE) 231*5f757f3fSDimitry Andric .addMBB(BreakBlock); 232*5f757f3fSDimitry Andric return *SuccessBlock; 233*5f757f3fSDimitry Andric } 234*5f757f3fSDimitry Andric llvm_unreachable("Unknown AuthCheckMethod enum"); 235*5f757f3fSDimitry Andric } 236*5f757f3fSDimitry Andric 237*5f757f3fSDimitry Andric unsigned llvm::AArch64PAuth::getCheckerSizeInBytes(AuthCheckMethod Method) { 238*5f757f3fSDimitry Andric switch (Method) { 239*5f757f3fSDimitry Andric case AuthCheckMethod::None: 240*5f757f3fSDimitry Andric return 0; 241*5f757f3fSDimitry Andric case AuthCheckMethod::DummyLoad: 242*5f757f3fSDimitry Andric return 4; 243*5f757f3fSDimitry Andric case AuthCheckMethod::HighBitsNoTBI: 244*5f757f3fSDimitry Andric return 12; 245*5f757f3fSDimitry Andric case AuthCheckMethod::XPACHint: 246*5f757f3fSDimitry Andric return 20; 247*5f757f3fSDimitry Andric } 248*5f757f3fSDimitry Andric llvm_unreachable("Unknown AuthCheckMethod enum"); 249*5f757f3fSDimitry Andric } 250*5f757f3fSDimitry Andric 251*5f757f3fSDimitry Andric bool AArch64PointerAuth::checkAuthenticatedLR( 252*5f757f3fSDimitry Andric MachineBasicBlock::iterator TI) const { 253*5f757f3fSDimitry Andric AuthCheckMethod Method = Subtarget->getAuthenticatedLRCheckMethod(); 254*5f757f3fSDimitry Andric 255*5f757f3fSDimitry Andric if (Method == AuthCheckMethod::None) 256*5f757f3fSDimitry Andric return false; 257*5f757f3fSDimitry Andric 258*5f757f3fSDimitry Andric // FIXME If FEAT_FPAC is implemented by the CPU, this check can be skipped. 259*5f757f3fSDimitry Andric 260*5f757f3fSDimitry Andric assert(!TI->getMF()->hasWinCFI() && "WinCFI is not yet supported"); 261*5f757f3fSDimitry Andric 262*5f757f3fSDimitry Andric // The following code may create a signing oracle: 263*5f757f3fSDimitry Andric // 264*5f757f3fSDimitry Andric // <authenticate LR> 265*5f757f3fSDimitry Andric // TCRETURN ; the callee may sign and spill the LR in its prologue 266*5f757f3fSDimitry Andric // 267*5f757f3fSDimitry Andric // To avoid generating a signing oracle, check the authenticated value 268*5f757f3fSDimitry Andric // before possibly re-signing it in the callee, as follows: 269*5f757f3fSDimitry Andric // 270*5f757f3fSDimitry Andric // <authenticate LR> 271*5f757f3fSDimitry Andric // <check if LR contains a valid address> 272*5f757f3fSDimitry Andric // b.<cond> break_block 273*5f757f3fSDimitry Andric // ret_block: 274*5f757f3fSDimitry Andric // TCRETURN 275*5f757f3fSDimitry Andric // break_block: 276*5f757f3fSDimitry Andric // brk <BrkOperand> 277*5f757f3fSDimitry Andric // 278*5f757f3fSDimitry Andric // or just 279*5f757f3fSDimitry Andric // 280*5f757f3fSDimitry Andric // <authenticate LR> 281*5f757f3fSDimitry Andric // ldr tmp, [lr] 282*5f757f3fSDimitry Andric // TCRETURN 283*5f757f3fSDimitry Andric 284*5f757f3fSDimitry Andric // TmpReg is chosen assuming X16 and X17 are dead after TI. 285*5f757f3fSDimitry Andric assert(AArch64InstrInfo::isTailCallReturnInst(*TI) && 286*5f757f3fSDimitry Andric "Tail call is expected"); 287*5f757f3fSDimitry Andric Register TmpReg = 288*5f757f3fSDimitry Andric TI->readsRegister(AArch64::X16, TRI) ? AArch64::X17 : AArch64::X16; 289*5f757f3fSDimitry Andric assert(!TI->readsRegister(TmpReg, TRI) && 290*5f757f3fSDimitry Andric "More than a single register is used by TCRETURN"); 291*5f757f3fSDimitry Andric 292*5f757f3fSDimitry Andric checkAuthenticatedRegister(TI, Method, AArch64::LR, TmpReg, /*UseIKey=*/true, 293*5f757f3fSDimitry Andric BrkOperand); 294*5f757f3fSDimitry Andric 295*5f757f3fSDimitry Andric return true; 296*5f757f3fSDimitry Andric } 297*5f757f3fSDimitry Andric 298*5f757f3fSDimitry Andric bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) { 299*5f757f3fSDimitry Andric const auto *MFnI = MF.getInfo<AArch64FunctionInfo>(); 300*5f757f3fSDimitry Andric 301*5f757f3fSDimitry Andric Subtarget = &MF.getSubtarget<AArch64Subtarget>(); 302*5f757f3fSDimitry Andric TII = Subtarget->getInstrInfo(); 303*5f757f3fSDimitry Andric TRI = Subtarget->getRegisterInfo(); 304*5f757f3fSDimitry Andric 305*5f757f3fSDimitry Andric SmallVector<MachineBasicBlock::instr_iterator> PAuthPseudoInstrs; 306*5f757f3fSDimitry Andric SmallVector<MachineBasicBlock::instr_iterator> TailCallInstrs; 307*5f757f3fSDimitry Andric 308*5f757f3fSDimitry Andric bool Modified = false; 309*5f757f3fSDimitry Andric bool HasAuthenticationInstrs = false; 310*5f757f3fSDimitry Andric 311*5f757f3fSDimitry Andric for (auto &MBB : MF) { 312*5f757f3fSDimitry Andric // Using instr_iterator to catch unsupported bundled TCRETURN* instructions 313*5f757f3fSDimitry Andric // instead of just skipping them. 314*5f757f3fSDimitry Andric for (auto &MI : MBB.instrs()) { 315*5f757f3fSDimitry Andric switch (MI.getOpcode()) { 316*5f757f3fSDimitry Andric default: 317*5f757f3fSDimitry Andric // Bundled TCRETURN* instructions (such as created by KCFI) 318*5f757f3fSDimitry Andric // are not supported yet, but no support is required if no 319*5f757f3fSDimitry Andric // PAUTH_EPILOGUE instructions exist in the same function. 320*5f757f3fSDimitry Andric // Skip the BUNDLE instruction itself (actual bundled instructions 321*5f757f3fSDimitry Andric // follow it in the instruction list). 322*5f757f3fSDimitry Andric if (MI.isBundle()) 323*5f757f3fSDimitry Andric continue; 324*5f757f3fSDimitry Andric if (AArch64InstrInfo::isTailCallReturnInst(MI)) 325*5f757f3fSDimitry Andric TailCallInstrs.push_back(MI.getIterator()); 326*5f757f3fSDimitry Andric break; 327*5f757f3fSDimitry Andric case AArch64::PAUTH_PROLOGUE: 328*5f757f3fSDimitry Andric case AArch64::PAUTH_EPILOGUE: 329*5f757f3fSDimitry Andric assert(!MI.isBundled()); 330*5f757f3fSDimitry Andric PAuthPseudoInstrs.push_back(MI.getIterator()); 331*5f757f3fSDimitry Andric break; 332*5f757f3fSDimitry Andric } 333*5f757f3fSDimitry Andric } 334*5f757f3fSDimitry Andric } 335*5f757f3fSDimitry Andric 336*5f757f3fSDimitry Andric for (auto It : PAuthPseudoInstrs) { 337*5f757f3fSDimitry Andric switch (It->getOpcode()) { 338*5f757f3fSDimitry Andric case AArch64::PAUTH_PROLOGUE: 339*5f757f3fSDimitry Andric signLR(MF, It); 340*5f757f3fSDimitry Andric break; 341*5f757f3fSDimitry Andric case AArch64::PAUTH_EPILOGUE: 342*5f757f3fSDimitry Andric authenticateLR(MF, It); 343*5f757f3fSDimitry Andric HasAuthenticationInstrs = true; 344*5f757f3fSDimitry Andric break; 345*5f757f3fSDimitry Andric default: 346*5f757f3fSDimitry Andric llvm_unreachable("Unhandled opcode"); 347*5f757f3fSDimitry Andric } 348*5f757f3fSDimitry Andric It->eraseFromParent(); 349*5f757f3fSDimitry Andric Modified = true; 350*5f757f3fSDimitry Andric } 351*5f757f3fSDimitry Andric 352*5f757f3fSDimitry Andric // FIXME Do we need to emit any PAuth-related epilogue code at all 353*5f757f3fSDimitry Andric // when SCS is enabled? 354*5f757f3fSDimitry Andric if (HasAuthenticationInstrs && 355*5f757f3fSDimitry Andric !MFnI->needsShadowCallStackPrologueEpilogue(MF)) { 356*5f757f3fSDimitry Andric for (auto TailCall : TailCallInstrs) { 357*5f757f3fSDimitry Andric assert(!TailCall->isBundled() && "Not yet supported"); 358*5f757f3fSDimitry Andric Modified |= checkAuthenticatedLR(TailCall); 359*5f757f3fSDimitry Andric } 360*5f757f3fSDimitry Andric } 361*5f757f3fSDimitry Andric 362*5f757f3fSDimitry Andric return Modified; 363*5f757f3fSDimitry Andric } 364