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/IR/Module.h" 38 #include "llvm/MC/MCInstrDesc.h" 39 #include "llvm/Support/Debug.h" 40 #include "llvm/TargetParser/Triple.h" 41 42 using namespace llvm; 43 44 #define PASS_KEY "x86-return-thunks" 45 #define DEBUG_TYPE PASS_KEY 46 47 namespace { 48 struct X86ReturnThunks final : public MachineFunctionPass { 49 static char ID; 50 X86ReturnThunks() : MachineFunctionPass(ID) {} 51 StringRef getPassName() const override { return "X86 Return Thunks"; } 52 bool runOnMachineFunction(MachineFunction &MF) override; 53 }; 54 } // namespace 55 56 char X86ReturnThunks::ID = 0; 57 58 bool X86ReturnThunks::runOnMachineFunction(MachineFunction &MF) { 59 LLVM_DEBUG(dbgs() << getPassName() << "\n"); 60 61 bool Modified = false; 62 63 if (!MF.getFunction().hasFnAttribute(llvm::Attribute::FnRetThunkExtern)) 64 return Modified; 65 66 StringRef ThunkName = "__x86_return_thunk"; 67 if (MF.getFunction().getName() == ThunkName) 68 return Modified; 69 70 const auto &ST = MF.getSubtarget<X86Subtarget>(); 71 const bool Is64Bit = ST.getTargetTriple().getArch() == Triple::x86_64; 72 const unsigned RetOpc = Is64Bit ? X86::RET64 : X86::RET32; 73 SmallVector<MachineInstr *, 16> Rets; 74 75 for (MachineBasicBlock &MBB : MF) 76 for (MachineInstr &Term : MBB.terminators()) 77 if (Term.getOpcode() == RetOpc) 78 Rets.push_back(&Term); 79 80 bool IndCS = 81 MF.getFunction().getParent()->getModuleFlag("indirect_branch_cs_prefix"); 82 const MCInstrDesc &CS = ST.getInstrInfo()->get(X86::CS_PREFIX); 83 const MCInstrDesc &JMP = ST.getInstrInfo()->get(X86::TAILJMPd); 84 85 for (MachineInstr *Ret : Rets) { 86 if (IndCS) 87 BuildMI(Ret->getParent(), Ret->getDebugLoc(), CS); 88 BuildMI(Ret->getParent(), Ret->getDebugLoc(), JMP) 89 .addExternalSymbol(ThunkName.data()); 90 Ret->eraseFromParent(); 91 Modified = true; 92 } 93 94 return Modified; 95 } 96 97 INITIALIZE_PASS(X86ReturnThunks, PASS_KEY, "X86 Return Thunks", false, false) 98 99 FunctionPass *llvm::createX86ReturnThunksPass() { 100 return new X86ReturnThunks(); 101 } 102