1 //==- X86ReturnThunks.cpp - Replace rets with thunks or inline thunks --=// 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 /// \file 9 /// 10 /// Pass that replaces ret instructions with a jmp to __x86_return_thunk. 11 /// 12 /// This corresponds to -mfunction-return=thunk-extern or 13 /// __attribute__((function_return("thunk-extern"). 14 /// 15 /// This pass is a minimal implementation necessary to help mitigate 16 /// RetBleed for the Linux kernel. 17 /// 18 /// Should support for thunk or thunk-inline be necessary in the future, then 19 /// this pass should be combined with x86-retpoline-thunks which already has 20 /// machinery to emit thunks. Until then, YAGNI. 21 /// 22 /// This pass is very similar to x86-lvi-ret. 23 /// 24 //===----------------------------------------------------------------------===// 25 26 #include "X86.h" 27 #include "X86InstrInfo.h" 28 #include "X86Subtarget.h" 29 #include "llvm/ADT/SmallVector.h" 30 #include "llvm/ADT/StringRef.h" 31 #include "llvm/CodeGen/MachineBasicBlock.h" 32 #include "llvm/CodeGen/MachineFunction.h" 33 #include "llvm/CodeGen/MachineFunctionPass.h" 34 #include "llvm/CodeGen/MachineInstr.h" 35 #include "llvm/CodeGen/MachineInstrBuilder.h" 36 #include "llvm/CodeGen/MachineModuleInfo.h" 37 #include "llvm/MC/MCInstrDesc.h" 38 #include "llvm/Support/Debug.h" 39 #include "llvm/TargetParser/Triple.h" 40 41 using namespace llvm; 42 43 #define PASS_KEY "x86-return-thunks" 44 #define DEBUG_TYPE PASS_KEY 45 46 namespace { 47 struct X86ReturnThunks final : public MachineFunctionPass { 48 static char ID; 49 X86ReturnThunks() : MachineFunctionPass(ID) {} 50 StringRef getPassName() const override { return "X86 Return Thunks"; } 51 bool runOnMachineFunction(MachineFunction &MF) override; 52 }; 53 } // namespace 54 55 char X86ReturnThunks::ID = 0; 56 57 bool X86ReturnThunks::runOnMachineFunction(MachineFunction &MF) { 58 LLVM_DEBUG(dbgs() << getPassName() << "\n"); 59 60 bool Modified = false; 61 62 if (!MF.getFunction().hasFnAttribute(llvm::Attribute::FnRetThunkExtern)) 63 return Modified; 64 65 StringRef ThunkName = "__x86_return_thunk"; 66 if (MF.getFunction().getName() == ThunkName) 67 return Modified; 68 69 const auto &ST = MF.getSubtarget<X86Subtarget>(); 70 const bool Is64Bit = ST.getTargetTriple().getArch() == Triple::x86_64; 71 const unsigned RetOpc = Is64Bit ? X86::RET64 : X86::RET32; 72 SmallVector<MachineInstr *, 16> Rets; 73 74 for (MachineBasicBlock &MBB : MF) 75 for (MachineInstr &Term : MBB.terminators()) 76 if (Term.getOpcode() == RetOpc) 77 Rets.push_back(&Term); 78 79 bool IndCS = 80 MF.getMMI().getModule()->getModuleFlag("indirect_branch_cs_prefix"); 81 const MCInstrDesc &CS = ST.getInstrInfo()->get(X86::CS_PREFIX); 82 const MCInstrDesc &JMP = ST.getInstrInfo()->get(X86::TAILJMPd); 83 84 for (MachineInstr *Ret : Rets) { 85 if (IndCS) 86 BuildMI(Ret->getParent(), Ret->getDebugLoc(), CS); 87 BuildMI(Ret->getParent(), Ret->getDebugLoc(), JMP) 88 .addExternalSymbol(ThunkName.data()); 89 Ret->eraseFromParent(); 90 Modified = true; 91 } 92 93 return Modified; 94 } 95 96 INITIALIZE_PASS(X86ReturnThunks, PASS_KEY, "X86 Return Thunks", false, false) 97 98 FunctionPass *llvm::createX86ReturnThunksPass() { 99 return new X86ReturnThunks(); 100 } 101