1*0946e70aSDimitry Andric //==- X86IndirectThunks.cpp - Construct indirect call/jump thunks for x86 --=// 2*0946e70aSDimitry Andric // 3*0946e70aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0946e70aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0946e70aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0946e70aSDimitry Andric // 7*0946e70aSDimitry Andric //===----------------------------------------------------------------------===// 8*0946e70aSDimitry Andric /// \file 9*0946e70aSDimitry Andric /// 10*0946e70aSDimitry Andric /// Pass that injects an MI thunk that is used to lower indirect calls in a way 11*0946e70aSDimitry Andric /// that prevents speculation on some x86 processors and can be used to mitigate 12*0946e70aSDimitry Andric /// security vulnerabilities due to targeted speculative execution and side 13*0946e70aSDimitry Andric /// channels such as CVE-2017-5715. 14*0946e70aSDimitry Andric /// 15*0946e70aSDimitry Andric /// Currently supported thunks include: 16*0946e70aSDimitry Andric /// - Retpoline -- A RET-implemented trampoline that lowers indirect calls 17*0946e70aSDimitry Andric /// - LVI Thunk -- A CALL/JMP-implemented thunk that forces load serialization 18*0946e70aSDimitry Andric /// before making an indirect call/jump 19*0946e70aSDimitry Andric /// 20*0946e70aSDimitry Andric /// Note that the reason that this is implemented as a MachineFunctionPass and 21*0946e70aSDimitry Andric /// not a ModulePass is that ModulePasses at this point in the LLVM X86 pipeline 22*0946e70aSDimitry Andric /// serialize all transformations, which can consume lots of memory. 23*0946e70aSDimitry Andric /// 24*0946e70aSDimitry Andric /// TODO(chandlerc): All of this code could use better comments and 25*0946e70aSDimitry Andric /// documentation. 26*0946e70aSDimitry Andric /// 27*0946e70aSDimitry Andric //===----------------------------------------------------------------------===// 28*0946e70aSDimitry Andric 29*0946e70aSDimitry Andric #include "X86.h" 30*0946e70aSDimitry Andric #include "X86InstrBuilder.h" 31*0946e70aSDimitry Andric #include "X86Subtarget.h" 32*0946e70aSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 33*0946e70aSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 34*0946e70aSDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 35*0946e70aSDimitry Andric #include "llvm/CodeGen/Passes.h" 36*0946e70aSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 37*0946e70aSDimitry Andric #include "llvm/IR/IRBuilder.h" 38*0946e70aSDimitry Andric #include "llvm/IR/Instructions.h" 39*0946e70aSDimitry Andric #include "llvm/IR/Module.h" 40*0946e70aSDimitry Andric #include "llvm/Support/CommandLine.h" 41*0946e70aSDimitry Andric #include "llvm/Support/Debug.h" 42*0946e70aSDimitry Andric #include "llvm/Support/raw_ostream.h" 43*0946e70aSDimitry Andric 44*0946e70aSDimitry Andric using namespace llvm; 45*0946e70aSDimitry Andric 46*0946e70aSDimitry Andric #define DEBUG_TYPE "x86-retpoline-thunks" 47*0946e70aSDimitry Andric 48*0946e70aSDimitry Andric static const char RetpolineNamePrefix[] = "__llvm_retpoline_"; 49*0946e70aSDimitry Andric static const char R11RetpolineName[] = "__llvm_retpoline_r11"; 50*0946e70aSDimitry Andric static const char EAXRetpolineName[] = "__llvm_retpoline_eax"; 51*0946e70aSDimitry Andric static const char ECXRetpolineName[] = "__llvm_retpoline_ecx"; 52*0946e70aSDimitry Andric static const char EDXRetpolineName[] = "__llvm_retpoline_edx"; 53*0946e70aSDimitry Andric static const char EDIRetpolineName[] = "__llvm_retpoline_edi"; 54*0946e70aSDimitry Andric 55*0946e70aSDimitry Andric static const char LVIThunkNamePrefix[] = "__llvm_lvi_thunk_"; 56*0946e70aSDimitry Andric static const char R11LVIThunkName[] = "__llvm_lvi_thunk_r11"; 57*0946e70aSDimitry Andric 58*0946e70aSDimitry Andric namespace { 59*0946e70aSDimitry Andric template <typename Derived> class ThunkInserter { 60*0946e70aSDimitry Andric Derived &getDerived() { return *static_cast<Derived *>(this); } 61*0946e70aSDimitry Andric 62*0946e70aSDimitry Andric protected: 63*0946e70aSDimitry Andric bool InsertedThunks; 64*0946e70aSDimitry Andric void doInitialization(Module &M) {} 65*0946e70aSDimitry Andric void createThunkFunction(MachineModuleInfo &MMI, StringRef Name); 66*0946e70aSDimitry Andric 67*0946e70aSDimitry Andric public: 68*0946e70aSDimitry Andric void init(Module &M) { 69*0946e70aSDimitry Andric InsertedThunks = false; 70*0946e70aSDimitry Andric getDerived().doInitialization(M); 71*0946e70aSDimitry Andric } 72*0946e70aSDimitry Andric // return `true` if `MMI` or `MF` was modified 73*0946e70aSDimitry Andric bool run(MachineModuleInfo &MMI, MachineFunction &MF); 74*0946e70aSDimitry Andric }; 75*0946e70aSDimitry Andric 76*0946e70aSDimitry Andric struct RetpolineThunkInserter : ThunkInserter<RetpolineThunkInserter> { 77*0946e70aSDimitry Andric const char *getThunkPrefix() { return RetpolineNamePrefix; } 78*0946e70aSDimitry Andric bool mayUseThunk(const MachineFunction &MF) { 79*0946e70aSDimitry Andric const auto &STI = MF.getSubtarget<X86Subtarget>(); 80*0946e70aSDimitry Andric return (STI.useRetpolineIndirectCalls() || 81*0946e70aSDimitry Andric STI.useRetpolineIndirectBranches()) && 82*0946e70aSDimitry Andric !STI.useRetpolineExternalThunk(); 83*0946e70aSDimitry Andric } 84*0946e70aSDimitry Andric void insertThunks(MachineModuleInfo &MMI); 85*0946e70aSDimitry Andric void populateThunk(MachineFunction &MF); 86*0946e70aSDimitry Andric }; 87*0946e70aSDimitry Andric 88*0946e70aSDimitry Andric struct LVIThunkInserter : ThunkInserter<LVIThunkInserter> { 89*0946e70aSDimitry Andric const char *getThunkPrefix() { return LVIThunkNamePrefix; } 90*0946e70aSDimitry Andric bool mayUseThunk(const MachineFunction &MF) { 91*0946e70aSDimitry Andric return MF.getSubtarget<X86Subtarget>().useLVIControlFlowIntegrity(); 92*0946e70aSDimitry Andric } 93*0946e70aSDimitry Andric void insertThunks(MachineModuleInfo &MMI) { 94*0946e70aSDimitry Andric createThunkFunction(MMI, R11LVIThunkName); 95*0946e70aSDimitry Andric } 96*0946e70aSDimitry Andric void populateThunk(MachineFunction &MF) { 97*0946e70aSDimitry Andric // Grab the entry MBB and erase any other blocks. O0 codegen appears to 98*0946e70aSDimitry Andric // generate two bbs for the entry block. 99*0946e70aSDimitry Andric MachineBasicBlock *Entry = &MF.front(); 100*0946e70aSDimitry Andric Entry->clear(); 101*0946e70aSDimitry Andric while (MF.size() > 1) 102*0946e70aSDimitry Andric MF.erase(std::next(MF.begin())); 103*0946e70aSDimitry Andric 104*0946e70aSDimitry Andric // This code mitigates LVI by replacing each indirect call/jump with a 105*0946e70aSDimitry Andric // direct call/jump to a thunk that looks like: 106*0946e70aSDimitry Andric // ``` 107*0946e70aSDimitry Andric // lfence 108*0946e70aSDimitry Andric // jmpq *%r11 109*0946e70aSDimitry Andric // ``` 110*0946e70aSDimitry Andric // This ensures that if the value in register %r11 was loaded from memory, 111*0946e70aSDimitry Andric // then the value in %r11 is (architecturally) correct prior to the jump. 112*0946e70aSDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo(); 113*0946e70aSDimitry Andric BuildMI(&MF.front(), DebugLoc(), TII->get(X86::LFENCE)); 114*0946e70aSDimitry Andric BuildMI(&MF.front(), DebugLoc(), TII->get(X86::JMP64r)).addReg(X86::R11); 115*0946e70aSDimitry Andric MF.front().addLiveIn(X86::R11); 116*0946e70aSDimitry Andric return; 117*0946e70aSDimitry Andric } 118*0946e70aSDimitry Andric }; 119*0946e70aSDimitry Andric 120*0946e70aSDimitry Andric class X86IndirectThunks : public MachineFunctionPass { 121*0946e70aSDimitry Andric public: 122*0946e70aSDimitry Andric static char ID; 123*0946e70aSDimitry Andric 124*0946e70aSDimitry Andric X86IndirectThunks() : MachineFunctionPass(ID) {} 125*0946e70aSDimitry Andric 126*0946e70aSDimitry Andric StringRef getPassName() const override { return "X86 Indirect Thunks"; } 127*0946e70aSDimitry Andric 128*0946e70aSDimitry Andric bool doInitialization(Module &M) override; 129*0946e70aSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 130*0946e70aSDimitry Andric 131*0946e70aSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 132*0946e70aSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 133*0946e70aSDimitry Andric AU.addRequired<MachineModuleInfoWrapperPass>(); 134*0946e70aSDimitry Andric AU.addPreserved<MachineModuleInfoWrapperPass>(); 135*0946e70aSDimitry Andric } 136*0946e70aSDimitry Andric 137*0946e70aSDimitry Andric private: 138*0946e70aSDimitry Andric std::tuple<RetpolineThunkInserter, LVIThunkInserter> TIs; 139*0946e70aSDimitry Andric 140*0946e70aSDimitry Andric // FIXME: When LLVM moves to C++17, these can become folds 141*0946e70aSDimitry Andric template <typename... ThunkInserterT> 142*0946e70aSDimitry Andric static void initTIs(Module &M, 143*0946e70aSDimitry Andric std::tuple<ThunkInserterT...> &ThunkInserters) { 144*0946e70aSDimitry Andric (void)std::initializer_list<int>{ 145*0946e70aSDimitry Andric (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...}; 146*0946e70aSDimitry Andric } 147*0946e70aSDimitry Andric template <typename... ThunkInserterT> 148*0946e70aSDimitry Andric static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF, 149*0946e70aSDimitry Andric std::tuple<ThunkInserterT...> &ThunkInserters) { 150*0946e70aSDimitry Andric bool Modified = false; 151*0946e70aSDimitry Andric (void)std::initializer_list<int>{ 152*0946e70aSDimitry Andric Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...}; 153*0946e70aSDimitry Andric return Modified; 154*0946e70aSDimitry Andric } 155*0946e70aSDimitry Andric }; 156*0946e70aSDimitry Andric 157*0946e70aSDimitry Andric } // end anonymous namespace 158*0946e70aSDimitry Andric 159*0946e70aSDimitry Andric void RetpolineThunkInserter::insertThunks(MachineModuleInfo &MMI) { 160*0946e70aSDimitry Andric if (MMI.getTarget().getTargetTriple().getArch() == Triple::x86_64) 161*0946e70aSDimitry Andric createThunkFunction(MMI, R11RetpolineName); 162*0946e70aSDimitry Andric else 163*0946e70aSDimitry Andric for (StringRef Name : {EAXRetpolineName, ECXRetpolineName, EDXRetpolineName, 164*0946e70aSDimitry Andric EDIRetpolineName}) 165*0946e70aSDimitry Andric createThunkFunction(MMI, Name); 166*0946e70aSDimitry Andric } 167*0946e70aSDimitry Andric 168*0946e70aSDimitry Andric void RetpolineThunkInserter::populateThunk(MachineFunction &MF) { 169*0946e70aSDimitry Andric bool Is64Bit = MF.getTarget().getTargetTriple().getArch() == Triple::x86_64; 170*0946e70aSDimitry Andric Register ThunkReg; 171*0946e70aSDimitry Andric if (Is64Bit) { 172*0946e70aSDimitry Andric assert(MF.getName() == "__llvm_retpoline_r11" && 173*0946e70aSDimitry Andric "Should only have an r11 thunk on 64-bit targets"); 174*0946e70aSDimitry Andric 175*0946e70aSDimitry Andric // __llvm_retpoline_r11: 176*0946e70aSDimitry Andric // callq .Lr11_call_target 177*0946e70aSDimitry Andric // .Lr11_capture_spec: 178*0946e70aSDimitry Andric // pause 179*0946e70aSDimitry Andric // lfence 180*0946e70aSDimitry Andric // jmp .Lr11_capture_spec 181*0946e70aSDimitry Andric // .align 16 182*0946e70aSDimitry Andric // .Lr11_call_target: 183*0946e70aSDimitry Andric // movq %r11, (%rsp) 184*0946e70aSDimitry Andric // retq 185*0946e70aSDimitry Andric ThunkReg = X86::R11; 186*0946e70aSDimitry Andric } else { 187*0946e70aSDimitry Andric // For 32-bit targets we need to emit a collection of thunks for various 188*0946e70aSDimitry Andric // possible scratch registers as well as a fallback that uses EDI, which is 189*0946e70aSDimitry Andric // normally callee saved. 190*0946e70aSDimitry Andric // __llvm_retpoline_eax: 191*0946e70aSDimitry Andric // calll .Leax_call_target 192*0946e70aSDimitry Andric // .Leax_capture_spec: 193*0946e70aSDimitry Andric // pause 194*0946e70aSDimitry Andric // jmp .Leax_capture_spec 195*0946e70aSDimitry Andric // .align 16 196*0946e70aSDimitry Andric // .Leax_call_target: 197*0946e70aSDimitry Andric // movl %eax, (%esp) # Clobber return addr 198*0946e70aSDimitry Andric // retl 199*0946e70aSDimitry Andric // 200*0946e70aSDimitry Andric // __llvm_retpoline_ecx: 201*0946e70aSDimitry Andric // ... # Same setup 202*0946e70aSDimitry Andric // movl %ecx, (%esp) 203*0946e70aSDimitry Andric // retl 204*0946e70aSDimitry Andric // 205*0946e70aSDimitry Andric // __llvm_retpoline_edx: 206*0946e70aSDimitry Andric // ... # Same setup 207*0946e70aSDimitry Andric // movl %edx, (%esp) 208*0946e70aSDimitry Andric // retl 209*0946e70aSDimitry Andric // 210*0946e70aSDimitry Andric // __llvm_retpoline_edi: 211*0946e70aSDimitry Andric // ... # Same setup 212*0946e70aSDimitry Andric // movl %edi, (%esp) 213*0946e70aSDimitry Andric // retl 214*0946e70aSDimitry Andric if (MF.getName() == EAXRetpolineName) 215*0946e70aSDimitry Andric ThunkReg = X86::EAX; 216*0946e70aSDimitry Andric else if (MF.getName() == ECXRetpolineName) 217*0946e70aSDimitry Andric ThunkReg = X86::ECX; 218*0946e70aSDimitry Andric else if (MF.getName() == EDXRetpolineName) 219*0946e70aSDimitry Andric ThunkReg = X86::EDX; 220*0946e70aSDimitry Andric else if (MF.getName() == EDIRetpolineName) 221*0946e70aSDimitry Andric ThunkReg = X86::EDI; 222*0946e70aSDimitry Andric else 223*0946e70aSDimitry Andric llvm_unreachable("Invalid thunk name on x86-32!"); 224*0946e70aSDimitry Andric } 225*0946e70aSDimitry Andric 226*0946e70aSDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo(); 227*0946e70aSDimitry Andric // Grab the entry MBB and erase any other blocks. O0 codegen appears to 228*0946e70aSDimitry Andric // generate two bbs for the entry block. 229*0946e70aSDimitry Andric MachineBasicBlock *Entry = &MF.front(); 230*0946e70aSDimitry Andric Entry->clear(); 231*0946e70aSDimitry Andric while (MF.size() > 1) 232*0946e70aSDimitry Andric MF.erase(std::next(MF.begin())); 233*0946e70aSDimitry Andric 234*0946e70aSDimitry Andric MachineBasicBlock *CaptureSpec = 235*0946e70aSDimitry Andric MF.CreateMachineBasicBlock(Entry->getBasicBlock()); 236*0946e70aSDimitry Andric MachineBasicBlock *CallTarget = 237*0946e70aSDimitry Andric MF.CreateMachineBasicBlock(Entry->getBasicBlock()); 238*0946e70aSDimitry Andric MCSymbol *TargetSym = MF.getContext().createTempSymbol(); 239*0946e70aSDimitry Andric MF.push_back(CaptureSpec); 240*0946e70aSDimitry Andric MF.push_back(CallTarget); 241*0946e70aSDimitry Andric 242*0946e70aSDimitry Andric const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; 243*0946e70aSDimitry Andric const unsigned RetOpc = Is64Bit ? X86::RETQ : X86::RETL; 244*0946e70aSDimitry Andric 245*0946e70aSDimitry Andric Entry->addLiveIn(ThunkReg); 246*0946e70aSDimitry Andric BuildMI(Entry, DebugLoc(), TII->get(CallOpc)).addSym(TargetSym); 247*0946e70aSDimitry Andric 248*0946e70aSDimitry Andric // The MIR verifier thinks that the CALL in the entry block will fall through 249*0946e70aSDimitry Andric // to CaptureSpec, so mark it as the successor. Technically, CaptureTarget is 250*0946e70aSDimitry Andric // the successor, but the MIR verifier doesn't know how to cope with that. 251*0946e70aSDimitry Andric Entry->addSuccessor(CaptureSpec); 252*0946e70aSDimitry Andric 253*0946e70aSDimitry Andric // In the capture loop for speculation, we want to stop the processor from 254*0946e70aSDimitry Andric // speculating as fast as possible. On Intel processors, the PAUSE instruction 255*0946e70aSDimitry Andric // will block speculation without consuming any execution resources. On AMD 256*0946e70aSDimitry Andric // processors, the PAUSE instruction is (essentially) a nop, so we also use an 257*0946e70aSDimitry Andric // LFENCE instruction which they have advised will stop speculation as well 258*0946e70aSDimitry Andric // with minimal resource utilization. We still end the capture with a jump to 259*0946e70aSDimitry Andric // form an infinite loop to fully guarantee that no matter what implementation 260*0946e70aSDimitry Andric // of the x86 ISA, speculating this code path never escapes. 261*0946e70aSDimitry Andric BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::PAUSE)); 262*0946e70aSDimitry Andric BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::LFENCE)); 263*0946e70aSDimitry Andric BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::JMP_1)).addMBB(CaptureSpec); 264*0946e70aSDimitry Andric CaptureSpec->setHasAddressTaken(); 265*0946e70aSDimitry Andric CaptureSpec->addSuccessor(CaptureSpec); 266*0946e70aSDimitry Andric 267*0946e70aSDimitry Andric CallTarget->addLiveIn(ThunkReg); 268*0946e70aSDimitry Andric CallTarget->setHasAddressTaken(); 269*0946e70aSDimitry Andric CallTarget->setAlignment(Align(16)); 270*0946e70aSDimitry Andric 271*0946e70aSDimitry Andric // Insert return address clobber 272*0946e70aSDimitry Andric const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr; 273*0946e70aSDimitry Andric const Register SPReg = Is64Bit ? X86::RSP : X86::ESP; 274*0946e70aSDimitry Andric addRegOffset(BuildMI(CallTarget, DebugLoc(), TII->get(MovOpc)), SPReg, false, 275*0946e70aSDimitry Andric 0) 276*0946e70aSDimitry Andric .addReg(ThunkReg); 277*0946e70aSDimitry Andric 278*0946e70aSDimitry Andric CallTarget->back().setPreInstrSymbol(MF, TargetSym); 279*0946e70aSDimitry Andric BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc)); 280*0946e70aSDimitry Andric } 281*0946e70aSDimitry Andric 282*0946e70aSDimitry Andric template <typename Derived> 283*0946e70aSDimitry Andric void ThunkInserter<Derived>::createThunkFunction(MachineModuleInfo &MMI, 284*0946e70aSDimitry Andric StringRef Name) { 285*0946e70aSDimitry Andric assert(Name.startswith(getDerived().getThunkPrefix()) && 286*0946e70aSDimitry Andric "Created a thunk with an unexpected prefix!"); 287*0946e70aSDimitry Andric 288*0946e70aSDimitry Andric Module &M = const_cast<Module &>(*MMI.getModule()); 289*0946e70aSDimitry Andric LLVMContext &Ctx = M.getContext(); 290*0946e70aSDimitry Andric auto Type = FunctionType::get(Type::getVoidTy(Ctx), false); 291*0946e70aSDimitry Andric Function *F = 292*0946e70aSDimitry Andric Function::Create(Type, GlobalValue::LinkOnceODRLinkage, Name, &M); 293*0946e70aSDimitry Andric F->setVisibility(GlobalValue::HiddenVisibility); 294*0946e70aSDimitry Andric F->setComdat(M.getOrInsertComdat(Name)); 295*0946e70aSDimitry Andric 296*0946e70aSDimitry Andric // Add Attributes so that we don't create a frame, unwind information, or 297*0946e70aSDimitry Andric // inline. 298*0946e70aSDimitry Andric AttrBuilder B; 299*0946e70aSDimitry Andric B.addAttribute(llvm::Attribute::NoUnwind); 300*0946e70aSDimitry Andric B.addAttribute(llvm::Attribute::Naked); 301*0946e70aSDimitry Andric F->addAttributes(llvm::AttributeList::FunctionIndex, B); 302*0946e70aSDimitry Andric 303*0946e70aSDimitry Andric // Populate our function a bit so that we can verify. 304*0946e70aSDimitry Andric BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F); 305*0946e70aSDimitry Andric IRBuilder<> Builder(Entry); 306*0946e70aSDimitry Andric 307*0946e70aSDimitry Andric Builder.CreateRetVoid(); 308*0946e70aSDimitry Andric 309*0946e70aSDimitry Andric // MachineFunctions/MachineBasicBlocks aren't created automatically for the 310*0946e70aSDimitry Andric // IR-level constructs we already made. Create them and insert them into the 311*0946e70aSDimitry Andric // module. 312*0946e70aSDimitry Andric MachineFunction &MF = MMI.getOrCreateMachineFunction(*F); 313*0946e70aSDimitry Andric MachineBasicBlock *EntryMBB = MF.CreateMachineBasicBlock(Entry); 314*0946e70aSDimitry Andric 315*0946e70aSDimitry Andric // Insert EntryMBB into MF. It's not in the module until we do this. 316*0946e70aSDimitry Andric MF.insert(MF.end(), EntryMBB); 317*0946e70aSDimitry Andric // Set MF properties. We never use vregs... 318*0946e70aSDimitry Andric MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); 319*0946e70aSDimitry Andric } 320*0946e70aSDimitry Andric 321*0946e70aSDimitry Andric template <typename Derived> 322*0946e70aSDimitry Andric bool ThunkInserter<Derived>::run(MachineModuleInfo &MMI, MachineFunction &MF) { 323*0946e70aSDimitry Andric // If MF is not a thunk, check to see if we need to insert a thunk. 324*0946e70aSDimitry Andric if (!MF.getName().startswith(getDerived().getThunkPrefix())) { 325*0946e70aSDimitry Andric // If we've already inserted a thunk, nothing else to do. 326*0946e70aSDimitry Andric if (InsertedThunks) 327*0946e70aSDimitry Andric return false; 328*0946e70aSDimitry Andric 329*0946e70aSDimitry Andric // Only add a thunk if one of the functions has the corresponding feature 330*0946e70aSDimitry Andric // enabled in its subtarget, and doesn't enable external thunks. 331*0946e70aSDimitry Andric // FIXME: Conditionalize on indirect calls so we don't emit a thunk when 332*0946e70aSDimitry Andric // nothing will end up calling it. 333*0946e70aSDimitry Andric // FIXME: It's a little silly to look at every function just to enumerate 334*0946e70aSDimitry Andric // the subtargets, but eventually we'll want to look at them for indirect 335*0946e70aSDimitry Andric // calls, so maybe this is OK. 336*0946e70aSDimitry Andric if (!getDerived().mayUseThunk(MF)) 337*0946e70aSDimitry Andric return false; 338*0946e70aSDimitry Andric 339*0946e70aSDimitry Andric getDerived().insertThunks(MMI); 340*0946e70aSDimitry Andric InsertedThunks = true; 341*0946e70aSDimitry Andric return true; 342*0946e70aSDimitry Andric } 343*0946e70aSDimitry Andric 344*0946e70aSDimitry Andric // If this *is* a thunk function, we need to populate it with the correct MI. 345*0946e70aSDimitry Andric getDerived().populateThunk(MF); 346*0946e70aSDimitry Andric return true; 347*0946e70aSDimitry Andric } 348*0946e70aSDimitry Andric 349*0946e70aSDimitry Andric FunctionPass *llvm::createX86IndirectThunksPass() { 350*0946e70aSDimitry Andric return new X86IndirectThunks(); 351*0946e70aSDimitry Andric } 352*0946e70aSDimitry Andric 353*0946e70aSDimitry Andric char X86IndirectThunks::ID = 0; 354*0946e70aSDimitry Andric 355*0946e70aSDimitry Andric bool X86IndirectThunks::doInitialization(Module &M) { 356*0946e70aSDimitry Andric initTIs(M, TIs); 357*0946e70aSDimitry Andric return false; 358*0946e70aSDimitry Andric } 359*0946e70aSDimitry Andric 360*0946e70aSDimitry Andric bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) { 361*0946e70aSDimitry Andric LLVM_DEBUG(dbgs() << getPassName() << '\n'); 362*0946e70aSDimitry Andric auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 363*0946e70aSDimitry Andric return runTIs(MMI, MF, TIs); 364*0946e70aSDimitry Andric } 365