1
- // ===---- IndirectThunks.h - Indirect Thunk Base Class ------- ---*- C++ -*-===//
1
+ // ===---- IndirectThunks.h - Indirect thunk insertion helpers ---*- C++ -*-===//
2
2
//
3
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
4
// See https://llvm.org/LICENSE.txt for license information.
7
7
// ===----------------------------------------------------------------------===//
8
8
// /
9
9
// / \file
10
- // / Contains a base class for Passes that inject an MI thunk.
10
+ // / Contains a base ThunkInserter class that simplifies injection of MI thunks
11
+ // / as well as a default implementation of MachineFunctionPass wrapping
12
+ // / several `ThunkInserter`s for targets to extend.
11
13
// /
12
14
// ===----------------------------------------------------------------------===//
13
15
14
16
#ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H
15
17
#define LLVM_CODEGEN_INDIRECTTHUNKS_H
16
18
17
19
#include " llvm/CodeGen/MachineFunction.h"
20
+ #include " llvm/CodeGen/MachineFunctionPass.h"
18
21
#include " llvm/CodeGen/MachineModuleInfo.h"
19
22
#include " llvm/IR/IRBuilder.h"
20
23
#include " llvm/IR/Module.h"
21
24
22
25
namespace llvm {
23
26
27
+ // / This class assists in inserting MI thunk functions into the module and
28
+ // / rewriting the existing machine functions to call these thunks.
29
+ // /
30
+ // / One of the common cases is implementing security mitigations that involve
31
+ // / replacing some machine code patterns with calls to special thunk functions.
32
+ // /
33
+ // / Inserting a module pass late in the codegen pipeline may increase memory
34
+ // / usage, as it serializes the transformations and forces preceding passes to
35
+ // / produce machine code for all functions before running the module pass.
36
+ // / For that reason, ThunkInserter can be driven by a MachineFunctionPass by
37
+ // / passing one MachineFunction at a time to its `run(MMI, MF)` method.
38
+ // / Then, the derived class should
39
+ // / * call createThunkFunction from its insertThunks method exactly once for
40
+ // / each of the thunk functions to be inserted
41
+ // / * populate the thunk in its populateThunk method
42
+ // /
43
+ // / Note that if some other pass is responsible for rewriting the functions,
44
+ // / the insertThunks method may simply create all possible thunks at once,
45
+ // / probably postponed until the first occurrence of possibly affected MF.
46
+ // /
47
+ // / Alternatively, insertThunks method can rewrite MF by itself and only insert
48
+ // / the thunks being called. In that case InsertedThunks variable can be used
49
+ // / to track which thunks were already inserted.
50
+ // /
51
+ // / In any case, the thunk function has to be inserted on behalf of some other
52
+ // / function and then populated on its own "iteration" later - this is because
53
+ // / MachineFunctionPass will see the newly created functions, but they first
54
+ // / have to go through the preceding passes from the same pass manager,
55
+ // / possibly even through the instruction selector.
56
+ //
57
+ // FIXME Maybe implement a documented and less surprising way of modifying
58
+ // the module from a MachineFunctionPass that is restricted to inserting
59
+ // completely new functions to the module.
24
60
template <typename Derived, typename InsertedThunksTy = bool >
25
61
class ThunkInserter {
26
62
Derived &getDerived () { return *static_cast <Derived *>(this ); }
27
63
28
- protected:
29
64
// A variable used to track whether (and possible which) thunks have been
30
65
// inserted so far. InsertedThunksTy is usually a bool, but can be other types
31
66
// to represent more than one type of thunk. Requires an |= operator to
32
67
// accumulate results.
33
68
InsertedThunksTy InsertedThunks;
34
- void doInitialization (Module &M) {}
69
+
70
+ protected:
71
+ // Interface for subclasses to use.
72
+
73
+ // / Create an empty thunk function.
74
+ // /
75
+ // / The new function will eventually be passed to populateThunk. If multiple
76
+ // / thunks are created, populateThunk can distinguish them by their names.
35
77
void createThunkFunction (MachineModuleInfo &MMI, StringRef Name,
36
78
bool Comdat = true , StringRef TargetAttrs = " " );
37
79
80
+ protected:
81
+ // Interface for subclasses to implement.
82
+ //
83
+ // Note: all functions are non-virtual and are called via getDerived().
84
+ // Note: only doInitialization() has an implementation.
85
+
86
+ // / Initializes thunk inserter.
87
+ void doInitialization (Module &M) {}
88
+
89
+ // / Returns common prefix for thunk function's names.
90
+ const char *getThunkPrefix (); // undefined
91
+
92
+ // / Checks if MF may use thunks (true - maybe, false - definitely not).
93
+ bool mayUseThunk (const MachineFunction &MF); // undefined
94
+
95
+ // / Rewrites the function if necessary, returns the set of thunks added.
96
+ InsertedThunksTy insertThunks (MachineModuleInfo &MMI, MachineFunction &MF,
97
+ InsertedThunksTy ExistingThunks); // undefined
98
+
99
+ // / Populate the thunk function with instructions.
100
+ // /
101
+ // / If multiple thunks are created, the content that must be inserted in the
102
+ // / thunk function body should be derived from the MF's name.
103
+ // /
104
+ // / Depending on the preceding passes in the pass manager, by the time
105
+ // / populateThunk is called, MF may have a few target-specific instructions
106
+ // / (such as a single MBB containing the return instruction).
107
+ void populateThunk (MachineFunction &MF); // undefined
108
+
38
109
public:
39
110
void init (Module &M) {
40
111
InsertedThunks = InsertedThunksTy{};
@@ -53,7 +124,7 @@ void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction(
53
124
54
125
Module &M = const_cast <Module &>(*MMI.getModule ());
55
126
LLVMContext &Ctx = M.getContext ();
56
- auto Type = FunctionType::get (Type::getVoidTy (Ctx), false );
127
+ auto * Type = FunctionType::get (Type::getVoidTy (Ctx), false );
57
128
Function *F = Function::Create (Type,
58
129
Comdat ? GlobalValue::LinkOnceODRLinkage
59
130
: GlobalValue::InternalLinkage,
@@ -95,19 +166,15 @@ bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
95
166
MachineFunction &MF) {
96
167
// If MF is not a thunk, check to see if we need to insert a thunk.
97
168
if (!MF.getName ().starts_with (getDerived ().getThunkPrefix ())) {
98
- // Only add a thunk if one of the functions has the corresponding feature
99
- // enabled in its subtarget, and doesn't enable external thunks. The target
100
- // can use InsertedThunks to detect whether relevant thunks have already
101
- // been inserted.
102
- // FIXME: Conditionalize on indirect calls so we don't emit a thunk when
103
- // nothing will end up calling it.
104
- // FIXME: It's a little silly to look at every function just to enumerate
105
- // the subtargets, but eventually we'll want to look at them for indirect
106
- // calls, so maybe this is OK.
107
- if (!getDerived ().mayUseThunk (MF, InsertedThunks))
169
+ // Only add thunks if one of the functions may use them.
170
+ if (!getDerived ().mayUseThunk (MF))
108
171
return false ;
109
172
110
- InsertedThunks |= getDerived ().insertThunks (MMI, MF);
173
+ // The target can use InsertedThunks to detect whether relevant thunks
174
+ // have already been inserted.
175
+ // FIXME: Provide the way for insertThunks to notify us whether it changed
176
+ // the MF, instead of conservatively assuming it did.
177
+ InsertedThunks |= getDerived ().insertThunks (MMI, MF, InsertedThunks);
111
178
return true ;
112
179
}
113
180
@@ -116,6 +183,40 @@ bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
116
183
return true ;
117
184
}
118
185
186
+ // / Basic implementation of MachineFunctionPass wrapping one or more
187
+ // / `ThunkInserter`s passed as type parameters.
188
+ template <typename ... Inserters>
189
+ class ThunkInserterPass : public MachineFunctionPass {
190
+ protected:
191
+ std::tuple<Inserters...> TIs;
192
+
193
+ ThunkInserterPass (char &ID) : MachineFunctionPass(ID) {}
194
+
195
+ public:
196
+ bool doInitialization (Module &M) override {
197
+ initTIs (M, TIs);
198
+ return false ;
199
+ }
200
+
201
+ bool runOnMachineFunction (MachineFunction &MF) override {
202
+ auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI ();
203
+ return runTIs (MMI, MF, TIs);
204
+ }
205
+
206
+ private:
207
+ template <typename ... ThunkInserterT>
208
+ static void initTIs (Module &M,
209
+ std::tuple<ThunkInserterT...> &ThunkInserters) {
210
+ (..., std::get<ThunkInserterT>(ThunkInserters).init (M));
211
+ }
212
+
213
+ template <typename ... ThunkInserterT>
214
+ static bool runTIs (MachineModuleInfo &MMI, MachineFunction &MF,
215
+ std::tuple<ThunkInserterT...> &ThunkInserters) {
216
+ return (0 | ... | std::get<ThunkInserterT>(ThunkInserters).run (MMI, MF));
217
+ }
218
+ };
219
+
119
220
} // namespace llvm
120
221
121
222
#endif
0 commit comments