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