|
|
|||
File indexing completed on 2026-05-10 08:43:28
0001 //===---- IndirectThunks.h - Indirect thunk insertion helpers ---*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 /// 0009 /// \file 0010 /// Contains a base ThunkInserter class that simplifies injection of MI thunks 0011 /// as well as a default implementation of MachineFunctionPass wrapping 0012 /// several `ThunkInserter`s for targets to extend. 0013 /// 0014 //===----------------------------------------------------------------------===// 0015 0016 #ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H 0017 #define LLVM_CODEGEN_INDIRECTTHUNKS_H 0018 0019 #include "llvm/CodeGen/MachineFunction.h" 0020 #include "llvm/CodeGen/MachineFunctionPass.h" 0021 #include "llvm/CodeGen/MachineModuleInfo.h" 0022 #include "llvm/IR/IRBuilder.h" 0023 #include "llvm/IR/Module.h" 0024 0025 namespace llvm { 0026 0027 /// This class assists in inserting MI thunk functions into the module and 0028 /// rewriting the existing machine functions to call these thunks. 0029 /// 0030 /// One of the common cases is implementing security mitigations that involve 0031 /// replacing some machine code patterns with calls to special thunk functions. 0032 /// 0033 /// Inserting a module pass late in the codegen pipeline may increase memory 0034 /// usage, as it serializes the transformations and forces preceding passes to 0035 /// produce machine code for all functions before running the module pass. 0036 /// For that reason, ThunkInserter can be driven by a MachineFunctionPass by 0037 /// passing one MachineFunction at a time to its `run(MMI, MF)` method. 0038 /// Then, the derived class should 0039 /// * call createThunkFunction from its insertThunks method exactly once for 0040 /// each of the thunk functions to be inserted 0041 /// * populate the thunk in its populateThunk method 0042 /// 0043 /// Note that if some other pass is responsible for rewriting the functions, 0044 /// the insertThunks method may simply create all possible thunks at once, 0045 /// probably postponed until the first occurrence of possibly affected MF. 0046 /// 0047 /// Alternatively, insertThunks method can rewrite MF by itself and only insert 0048 /// the thunks being called. In that case InsertedThunks variable can be used 0049 /// to track which thunks were already inserted. 0050 /// 0051 /// In any case, the thunk function has to be inserted on behalf of some other 0052 /// function and then populated on its own "iteration" later - this is because 0053 /// MachineFunctionPass will see the newly created functions, but they first 0054 /// have to go through the preceding passes from the same pass manager, 0055 /// possibly even through the instruction selector. 0056 // 0057 // FIXME Maybe implement a documented and less surprising way of modifying 0058 // the module from a MachineFunctionPass that is restricted to inserting 0059 // completely new functions to the module. 0060 template <typename Derived, typename InsertedThunksTy = bool> 0061 class ThunkInserter { 0062 Derived &getDerived() { return *static_cast<Derived *>(this); } 0063 0064 // A variable used to track whether (and possible which) thunks have been 0065 // inserted so far. InsertedThunksTy is usually a bool, but can be other types 0066 // to represent more than one type of thunk. Requires an |= operator to 0067 // accumulate results. 0068 InsertedThunksTy InsertedThunks; 0069 0070 protected: 0071 // Interface for subclasses to use. 0072 0073 /// Create an empty thunk function. 0074 /// 0075 /// The new function will eventually be passed to populateThunk. If multiple 0076 /// thunks are created, populateThunk can distinguish them by their names. 0077 void createThunkFunction(MachineModuleInfo &MMI, StringRef Name, 0078 bool Comdat = true, StringRef TargetAttrs = ""); 0079 0080 protected: 0081 // Interface for subclasses to implement. 0082 // 0083 // Note: all functions are non-virtual and are called via getDerived(). 0084 // Note: only doInitialization() has an implementation. 0085 0086 /// Initializes thunk inserter. 0087 void doInitialization(Module &M) {} 0088 0089 /// Returns common prefix for thunk function's names. 0090 const char *getThunkPrefix(); // undefined 0091 0092 /// Checks if MF may use thunks (true - maybe, false - definitely not). 0093 bool mayUseThunk(const MachineFunction &MF); // undefined 0094 0095 /// Rewrites the function if necessary, returns the set of thunks added. 0096 InsertedThunksTy insertThunks(MachineModuleInfo &MMI, MachineFunction &MF, 0097 InsertedThunksTy ExistingThunks); // undefined 0098 0099 /// Populate the thunk function with instructions. 0100 /// 0101 /// If multiple thunks are created, the content that must be inserted in the 0102 /// thunk function body should be derived from the MF's name. 0103 /// 0104 /// Depending on the preceding passes in the pass manager, by the time 0105 /// populateThunk is called, MF may have a few target-specific instructions 0106 /// (such as a single MBB containing the return instruction). 0107 void populateThunk(MachineFunction &MF); // undefined 0108 0109 public: 0110 void init(Module &M) { 0111 InsertedThunks = InsertedThunksTy{}; 0112 getDerived().doInitialization(M); 0113 } 0114 // return `true` if `MMI` or `MF` was modified 0115 bool run(MachineModuleInfo &MMI, MachineFunction &MF); 0116 }; 0117 0118 template <typename Derived, typename InsertedThunksTy> 0119 void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction( 0120 MachineModuleInfo &MMI, StringRef Name, bool Comdat, 0121 StringRef TargetAttrs) { 0122 assert(Name.starts_with(getDerived().getThunkPrefix()) && 0123 "Created a thunk with an unexpected prefix!"); 0124 0125 Module &M = const_cast<Module &>(*MMI.getModule()); 0126 LLVMContext &Ctx = M.getContext(); 0127 auto *Type = FunctionType::get(Type::getVoidTy(Ctx), false); 0128 Function *F = Function::Create(Type, 0129 Comdat ? GlobalValue::LinkOnceODRLinkage 0130 : GlobalValue::InternalLinkage, 0131 Name, &M); 0132 if (Comdat) { 0133 F->setVisibility(GlobalValue::HiddenVisibility); 0134 F->setComdat(M.getOrInsertComdat(Name)); 0135 } 0136 0137 // Add Attributes so that we don't create a frame, unwind information, or 0138 // inline. 0139 AttrBuilder B(Ctx); 0140 B.addAttribute(llvm::Attribute::NoUnwind); 0141 B.addAttribute(llvm::Attribute::Naked); 0142 if (TargetAttrs != "") 0143 B.addAttribute("target-features", TargetAttrs); 0144 F->addFnAttrs(B); 0145 0146 // Populate our function a bit so that we can verify. 0147 BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F); 0148 IRBuilder<> Builder(Entry); 0149 0150 Builder.CreateRetVoid(); 0151 0152 // MachineFunctions aren't created automatically for the IR-level constructs 0153 // we already made. Create them and insert them into the module. 0154 MachineFunction &MF = MMI.getOrCreateMachineFunction(*F); 0155 // A MachineBasicBlock must not be created for the Entry block; code 0156 // generation from an empty naked function in C source code also does not 0157 // generate one. At least GlobalISel asserts if this invariant isn't 0158 // respected. 0159 0160 // Set MF properties. We never use vregs... 0161 MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); 0162 } 0163 0164 template <typename Derived, typename InsertedThunksTy> 0165 bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI, 0166 MachineFunction &MF) { 0167 // If MF is not a thunk, check to see if we need to insert a thunk. 0168 if (!MF.getName().starts_with(getDerived().getThunkPrefix())) { 0169 // Only add thunks if one of the functions may use them. 0170 if (!getDerived().mayUseThunk(MF)) 0171 return false; 0172 0173 // The target can use InsertedThunks to detect whether relevant thunks 0174 // have already been inserted. 0175 // FIXME: Provide the way for insertThunks to notify us whether it changed 0176 // the MF, instead of conservatively assuming it did. 0177 InsertedThunks |= getDerived().insertThunks(MMI, MF, InsertedThunks); 0178 return true; 0179 } 0180 0181 // If this *is* a thunk function, we need to populate it with the correct MI. 0182 getDerived().populateThunk(MF); 0183 return true; 0184 } 0185 0186 /// Basic implementation of MachineFunctionPass wrapping one or more 0187 /// `ThunkInserter`s passed as type parameters. 0188 template <typename... Inserters> 0189 class ThunkInserterPass : public MachineFunctionPass { 0190 protected: 0191 std::tuple<Inserters...> TIs; 0192 0193 ThunkInserterPass(char &ID) : MachineFunctionPass(ID) {} 0194 0195 public: 0196 bool doInitialization(Module &M) override { 0197 initTIs(M, TIs); 0198 return false; 0199 } 0200 0201 bool runOnMachineFunction(MachineFunction &MF) override { 0202 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 0203 return runTIs(MMI, MF, TIs); 0204 } 0205 0206 private: 0207 template <typename... ThunkInserterT> 0208 static void initTIs(Module &M, 0209 std::tuple<ThunkInserterT...> &ThunkInserters) { 0210 (..., std::get<ThunkInserterT>(ThunkInserters).init(M)); 0211 } 0212 0213 template <typename... ThunkInserterT> 0214 static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF, 0215 std::tuple<ThunkInserterT...> &ThunkInserters) { 0216 return (0 | ... | std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)); 0217 } 0218 }; 0219 0220 } // namespace llvm 0221 0222 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|