@@ -81,7 +81,19 @@ enum EdgeKind_i386 : Edge::Kind {
81
81
// /
82
82
PCRel16,
83
83
84
- // / A 64-bit GOT delta.
84
+ // / A 32-bit delta.
85
+ // /
86
+ // / Delta from the fixup to the target.
87
+ // /
88
+ // / Fixup expression:
89
+ // / Fixup <- Target - Fixup + Addend : int64
90
+ // /
91
+ // / Errors:
92
+ // / - The result of the fixup expression must fit into an int32, otherwise
93
+ // / an out-of-range error will be returned.
94
+ Delta32,
95
+
96
+ // / A 32-bit GOT delta.
85
97
// /
86
98
// / Delta from the global offset table to the target.
87
99
// /
@@ -92,6 +104,26 @@ enum EdgeKind_i386 : Edge::Kind {
92
104
// / - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
93
105
// / symbol was not been defined.
94
106
Delta32FromGOT,
107
+
108
+ // / A GOT entry offset within GOT getter/constructor, transformed to
109
+ // / Delta32FromGOT pointing at the GOT entry for the original target.
110
+ // /
111
+ // / Indicates that this edge should be transformed into a Delta32FromGOT
112
+ // / targeting the GOT entry for the edge's current target, maintaining the
113
+ // / same addend.
114
+ // / A GOT entry for the target should be created if one does not already
115
+ // / exist.
116
+ // /
117
+ // / Edges of this kind are usually handled by a GOT builder pass inserted by
118
+ // / default
119
+ // /
120
+ // / Fixup expression:
121
+ // / NONE
122
+ // /
123
+ // / Errors:
124
+ // / - *ASSERTION* Failure to handle edges of this kind prior to the fixup
125
+ // / phase will result in an assert/unreachable during the fixup phase
126
+ RequestGOTAndTransformToDelta32FromGOT,
95
127
};
96
128
97
129
// / Returns a string name for the given i386 edge. For debugging purposes
@@ -110,7 +142,8 @@ inline bool isInRangeForImmS16(int32_t Value) {
110
142
}
111
143
112
144
// / Apply fixup expression for edge to block content.
113
- inline Error applyFixup (LinkGraph &G, Block &B, const Edge &E) {
145
+ inline Error applyFixup (LinkGraph &G, Block &B, const Edge &E,
146
+ const Symbol *GOTSymbol) {
114
147
using namespace i386 ;
115
148
using namespace llvm ::support;
116
149
@@ -155,6 +188,20 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
155
188
break ;
156
189
}
157
190
191
+ case i386::Delta32: {
192
+ int32_t Value = E.getTarget ().getAddress () - FixupAddress + E.getAddend ();
193
+ *(little32_t *)FixupPtr = Value;
194
+ break ;
195
+ }
196
+
197
+ case i386::Delta32FromGOT: {
198
+ assert (GOTSymbol && " No GOT section symbol" );
199
+ int32_t Value =
200
+ E.getTarget ().getAddress () - GOTSymbol->getAddress () + E.getAddend ();
201
+ *(little32_t *)FixupPtr = Value;
202
+ break ;
203
+ }
204
+
158
205
default :
159
206
return make_error<JITLinkError>(
160
207
" In graph " + G.getName () + " , section " + B.getSection ().getName () +
@@ -163,6 +210,79 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
163
210
164
211
return Error::success ();
165
212
}
213
+
214
+ // / i386 pointer size.
215
+ constexpr uint32_t PointerSize = 4 ;
216
+
217
+ // / i386 null pointer content.
218
+ extern const char NullPointerContent[PointerSize];
219
+
220
+ // / Creates a new pointer block in the given section and returns an anonymous
221
+ // / symbol pointing to it.
222
+ // /
223
+ // / If InitialTarget is given then an Pointer32 relocation will be added to the
224
+ // / block pointing at InitialTarget.
225
+ // /
226
+ // / The pointer block will have the following default values:
227
+ // / alignment: 32-bit
228
+ // / alignment-offset: 0
229
+ // / address: highest allowable (~7U)
230
+ inline Symbol &createAnonymousPointer (LinkGraph &G, Section &PointerSection,
231
+ Symbol *InitialTarget = nullptr ,
232
+ uint64_t InitialAddend = 0 ) {
233
+ auto &B = G.createContentBlock (PointerSection, NullPointerContent,
234
+ orc::ExecutorAddr (), 8 , 0 );
235
+ if (InitialTarget)
236
+ B.addEdge (Pointer32, 0 , *InitialTarget, InitialAddend);
237
+ return G.addAnonymousSymbol (B, 0 , PointerSize, false , false );
238
+ }
239
+
240
+ // / Global Offset Table Builder.
241
+ class GOTTableManager : public TableManager <GOTTableManager> {
242
+ public:
243
+ static StringRef getSectionName () { return " $__GOT" ; }
244
+
245
+ bool visitEdge (LinkGraph &G, Block *B, Edge &E) {
246
+ Edge::Kind KindToSet = Edge::Invalid;
247
+ switch (E.getKind ()) {
248
+ case i386::Delta32FromGOT: {
249
+ // we need to make sure that the GOT section exists, but don't otherwise
250
+ // need to fix up this edge
251
+ getGOTSection (G);
252
+ return false ;
253
+ }
254
+ case i386::RequestGOTAndTransformToDelta32FromGOT:
255
+ KindToSet = i386::Delta32FromGOT;
256
+ break ;
257
+ default :
258
+ return false ;
259
+ }
260
+ assert (KindToSet != Edge::Invalid &&
261
+ " Fell through switch, but no new kind to set" );
262
+ DEBUG_WITH_TYPE (" jitlink" , {
263
+ dbgs () << " Fixing " << G.getEdgeKindName (E.getKind ()) << " edge at "
264
+ << B->getFixupAddress (E) << " (" << B->getAddress () << " + "
265
+ << formatv (" {0:x}" , E.getOffset ()) << " )\n " ;
266
+ });
267
+ E.setKind (KindToSet);
268
+ E.setTarget (getEntryForTarget (G, E.getTarget ()));
269
+ return true ;
270
+ }
271
+
272
+ Symbol &createEntry (LinkGraph &G, Symbol &Target) {
273
+ return createAnonymousPointer (G, getGOTSection (G), &Target);
274
+ }
275
+
276
+ private:
277
+ Section &getGOTSection (LinkGraph &G) {
278
+ if (!GOTSection)
279
+ GOTSection = &G.createSection (getSectionName (), orc::MemProt::Read);
280
+ return *GOTSection;
281
+ }
282
+
283
+ Section *GOTSection = nullptr ;
284
+ };
285
+
166
286
} // namespace llvm::jitlink::i386
167
287
168
288
#endif // LLVM_EXECUTIONENGINE_JITLINK_I386_H
0 commit comments