xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1fe6060f1SDimitry Andric //===-- x86_64.h - Generic JITLink x86-64 edge kinds, utilities -*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // Generic utilities for graphs representing x86-64 objects.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric 
13fe6060f1SDimitry Andric #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
14fe6060f1SDimitry Andric #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17349cc55cSDimitry Andric #include "llvm/ExecutionEngine/JITLink/TableManager.h"
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric namespace llvm {
20fe6060f1SDimitry Andric namespace jitlink {
21fe6060f1SDimitry Andric namespace x86_64 {
22fe6060f1SDimitry Andric 
23fe6060f1SDimitry Andric /// Represents x86-64 fixups and other x86-64-specific edge kinds.
24fe6060f1SDimitry Andric enum EdgeKind_x86_64 : Edge::Kind {
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric   /// A plain 64-bit pointer value relocation.
27fe6060f1SDimitry Andric   ///
28fe6060f1SDimitry Andric   /// Fixup expression:
29fe6060f1SDimitry Andric   ///   Fixup <- Target + Addend : uint64
30fe6060f1SDimitry Andric   ///
31fe6060f1SDimitry Andric   Pointer64 = Edge::FirstRelocation,
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric   /// A plain 32-bit pointer value relocation.
34fe6060f1SDimitry Andric   ///
35fe6060f1SDimitry Andric   /// Fixup expression:
36fe6060f1SDimitry Andric   ///   Fixup <- Target + Addend : uint32
37fe6060f1SDimitry Andric   ///
38fe6060f1SDimitry Andric   /// Errors:
39fe6060f1SDimitry Andric   ///   - The target must reside in the low 32-bits of the address space,
40fe6060f1SDimitry Andric   ///     otherwise an out-of-range error will be returned.
41fe6060f1SDimitry Andric   ///
42fe6060f1SDimitry Andric   Pointer32,
43fe6060f1SDimitry Andric 
44349cc55cSDimitry Andric   /// A signed 32-bit pointer value relocation
45349cc55cSDimitry Andric   ///
46349cc55cSDimitry Andric   /// Fixup expression:
47349cc55cSDimitry Andric   ///   Fixup <- Target + Addend : int32
48349cc55cSDimitry Andric   ///
49349cc55cSDimitry Andric   /// Errors:
50349cc55cSDimitry Andric   ///   - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of
51349cc55cSDimitry Andric   ///   the address space, otherwise an out-of-range error will be returned.
52349cc55cSDimitry Andric   Pointer32Signed,
53349cc55cSDimitry Andric 
54bdd1243dSDimitry Andric   /// A plain 16-bit pointer value relocation.
55bdd1243dSDimitry Andric   ///
56bdd1243dSDimitry Andric   /// Fixup expression:
57bdd1243dSDimitry Andric   ///   Fixup <- Target + Addend : uint16
58bdd1243dSDimitry Andric   ///
59bdd1243dSDimitry Andric   /// Errors:
60bdd1243dSDimitry Andric   ///   - The target must reside in the low 16-bits of the address space,
61bdd1243dSDimitry Andric   ///     otherwise an out-of-range error will be returned.
62bdd1243dSDimitry Andric   ///
63bdd1243dSDimitry Andric   Pointer16,
64bdd1243dSDimitry Andric 
6506c3fb27SDimitry Andric   /// A plain 8-bit pointer value relocation.
6606c3fb27SDimitry Andric   ///
6706c3fb27SDimitry Andric   /// Fixup expression:
6806c3fb27SDimitry Andric   ///   Fixup <- Target + Addend : uint8
6906c3fb27SDimitry Andric   ///
7006c3fb27SDimitry Andric   /// Errors:
7106c3fb27SDimitry Andric   ///   - The target must reside in the low 8-bits of the address space,
7206c3fb27SDimitry Andric   ///     otherwise an out-of-range error will be returned.
7306c3fb27SDimitry Andric   ///
7406c3fb27SDimitry Andric   Pointer8,
7506c3fb27SDimitry Andric 
76fe6060f1SDimitry Andric   /// A 64-bit delta.
77fe6060f1SDimitry Andric   ///
78fe6060f1SDimitry Andric   /// Delta from the fixup to the target.
79fe6060f1SDimitry Andric   ///
80fe6060f1SDimitry Andric   /// Fixup expression:
81fe6060f1SDimitry Andric   ///   Fixup <- Target - Fixup + Addend : int64
82fe6060f1SDimitry Andric   ///
83fe6060f1SDimitry Andric   Delta64,
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric   /// A 32-bit delta.
86fe6060f1SDimitry Andric   ///
87fe6060f1SDimitry Andric   /// Delta from the fixup to the target.
88fe6060f1SDimitry Andric   ///
89fe6060f1SDimitry Andric   /// Fixup expression:
90*0fca6ea1SDimitry Andric   ///   Fixup <- Target - Fixup + Addend : int32
91fe6060f1SDimitry Andric   ///
92fe6060f1SDimitry Andric   /// Errors:
93fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
94fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
95fe6060f1SDimitry Andric   ///
96fe6060f1SDimitry Andric   Delta32,
97fe6060f1SDimitry Andric 
98*0fca6ea1SDimitry Andric   /// An 8-bit delta.
99*0fca6ea1SDimitry Andric   ///
100*0fca6ea1SDimitry Andric   /// Delta from the fixup to the target.
101*0fca6ea1SDimitry Andric   ///
102*0fca6ea1SDimitry Andric   /// Fixup expression:
103*0fca6ea1SDimitry Andric   ///   Fixup <- Target - Fixup + Addend : int8
104*0fca6ea1SDimitry Andric   ///
105*0fca6ea1SDimitry Andric   /// Errors:
106*0fca6ea1SDimitry Andric   ///   - The result of the fixup expression must fit into an int8, otherwise
107*0fca6ea1SDimitry Andric   ///     an out-of-range error will be returned.
108*0fca6ea1SDimitry Andric   ///
109*0fca6ea1SDimitry Andric   Delta8,
110*0fca6ea1SDimitry Andric 
111fe6060f1SDimitry Andric   /// A 64-bit negative delta.
112fe6060f1SDimitry Andric   ///
113fe6060f1SDimitry Andric   /// Delta from target back to the fixup.
114fe6060f1SDimitry Andric   ///
115fe6060f1SDimitry Andric   /// Fixup expression:
116fe6060f1SDimitry Andric   ///   Fixup <- Fixup - Target + Addend : int64
117fe6060f1SDimitry Andric   ///
118fe6060f1SDimitry Andric   NegDelta64,
119fe6060f1SDimitry Andric 
120fe6060f1SDimitry Andric   /// A 32-bit negative delta.
121fe6060f1SDimitry Andric   ///
122fe6060f1SDimitry Andric   /// Delta from the target back to the fixup.
123fe6060f1SDimitry Andric   ///
124fe6060f1SDimitry Andric   /// Fixup expression:
125fe6060f1SDimitry Andric   ///   Fixup <- Fixup - Target + Addend : int32
126fe6060f1SDimitry Andric   ///
127fe6060f1SDimitry Andric   /// Errors:
128fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
129fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
130fe6060f1SDimitry Andric   NegDelta32,
131fe6060f1SDimitry Andric 
132349cc55cSDimitry Andric   /// A 64-bit GOT delta.
133349cc55cSDimitry Andric   ///
134349cc55cSDimitry Andric   /// Delta from the global offset table to the target
135349cc55cSDimitry Andric   ///
136349cc55cSDimitry Andric   /// Fixup expression:
137349cc55cSDimitry Andric   ///   Fixup <- Target - GOTSymbol + Addend : int64
138349cc55cSDimitry Andric   ///
139349cc55cSDimitry Andric   /// Errors:
140349cc55cSDimitry Andric   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
141349cc55cSDimitry Andric   ///     symbol was not been defined.
142349cc55cSDimitry Andric   Delta64FromGOT,
143349cc55cSDimitry Andric 
144fe6060f1SDimitry Andric   /// A 32-bit PC-relative branch.
145fe6060f1SDimitry Andric   ///
146fe6060f1SDimitry Andric   /// Represents a PC-relative call or branch to a target. This can be used to
147fe6060f1SDimitry Andric   /// identify, record, and/or patch call sites.
148fe6060f1SDimitry Andric   ///
149fe6060f1SDimitry Andric   /// The fixup expression for this kind includes an implicit offset to account
150fe6060f1SDimitry Andric   /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
151fe6060f1SDimitry Andric   /// T and addend zero is a call/branch to the start (offset zero) of T.
152fe6060f1SDimitry Andric   ///
153fe6060f1SDimitry Andric   /// Fixup expression:
154fe6060f1SDimitry Andric   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
155fe6060f1SDimitry Andric   ///
156fe6060f1SDimitry Andric   /// Errors:
157fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
158fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
159fe6060f1SDimitry Andric   ///
160fe6060f1SDimitry Andric   BranchPCRel32,
161fe6060f1SDimitry Andric 
162972a253aSDimitry Andric   /// A 32-bit PC-relative relocation.
163972a253aSDimitry Andric   ///
164972a253aSDimitry Andric   /// Represents a data/control flow instruction using PC-relative addressing
165972a253aSDimitry Andric   /// to a target.
166972a253aSDimitry Andric   ///
167972a253aSDimitry Andric   /// The fixup expression for this kind includes an implicit offset to account
168972a253aSDimitry Andric   /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
169972a253aSDimitry Andric   /// T and addend zero is a call/branch to the start (offset zero) of T.
170972a253aSDimitry Andric   ///
171972a253aSDimitry Andric   /// Fixup expression:
172972a253aSDimitry Andric   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
173972a253aSDimitry Andric   ///
174972a253aSDimitry Andric   /// Errors:
175972a253aSDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
176972a253aSDimitry Andric   ///     an out-of-range error will be returned.
177972a253aSDimitry Andric   ///
178972a253aSDimitry Andric   PCRel32,
179972a253aSDimitry Andric 
180fe6060f1SDimitry Andric   /// A 32-bit PC-relative branch to a pointer jump stub.
181fe6060f1SDimitry Andric   ///
182fe6060f1SDimitry Andric   /// The target of this relocation should be a pointer jump stub of the form:
183fe6060f1SDimitry Andric   ///
184fe6060f1SDimitry Andric   /// \code{.s}
185fe6060f1SDimitry Andric   ///   .text
186fe6060f1SDimitry Andric   ///   jmpq *tgtptr(%rip)
187fe6060f1SDimitry Andric   ///   ; ...
188fe6060f1SDimitry Andric   ///
189fe6060f1SDimitry Andric   ///   .data
190fe6060f1SDimitry Andric   ///   tgtptr:
191fe6060f1SDimitry Andric   ///     .quad 0
192fe6060f1SDimitry Andric   /// \endcode
193fe6060f1SDimitry Andric   ///
194fe6060f1SDimitry Andric   /// This edge kind has the same fixup expression as BranchPCRel32, but further
195fe6060f1SDimitry Andric   /// identifies the call/branch as being to a pointer jump stub. For edges of
196fe6060f1SDimitry Andric   /// this kind the jump stub should not be bypassed (use
197349cc55cSDimitry Andric   /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
198fe6060f1SDimitry Andric   /// target may be recorded to allow manipulation at runtime.
199fe6060f1SDimitry Andric   ///
200fe6060f1SDimitry Andric   /// Fixup expression:
201fe6060f1SDimitry Andric   ///   Fixup <- Target - Fixup + Addend - 4 : int32
202fe6060f1SDimitry Andric   ///
203fe6060f1SDimitry Andric   /// Errors:
204fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
205fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
206fe6060f1SDimitry Andric   ///
207fe6060f1SDimitry Andric   BranchPCRel32ToPtrJumpStub,
208fe6060f1SDimitry Andric 
209fe6060f1SDimitry Andric   /// A relaxable version of BranchPCRel32ToPtrJumpStub.
210fe6060f1SDimitry Andric   ///
211fe6060f1SDimitry Andric   /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
212fe6060f1SDimitry Andric   /// but identifies the call/branch as being to a pointer jump stub that may be
213349cc55cSDimitry Andric   /// bypassed with a direct jump to the ultimate target if the ultimate target
214349cc55cSDimitry Andric   /// is within range of the fixup location.
215fe6060f1SDimitry Andric   ///
216fe6060f1SDimitry Andric   /// Fixup expression:
217fe6060f1SDimitry Andric   ///   Fixup <- Target - Fixup + Addend - 4: int32
218fe6060f1SDimitry Andric   ///
219fe6060f1SDimitry Andric   /// Errors:
220fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
221fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
222fe6060f1SDimitry Andric   ///
223349cc55cSDimitry Andric   BranchPCRel32ToPtrJumpStubBypassable,
224fe6060f1SDimitry Andric 
225fe6060f1SDimitry Andric   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
226fe6060f1SDimitry Andric   /// entry for the original target.
227fe6060f1SDimitry Andric   ///
228fe6060f1SDimitry Andric   /// Indicates that this edge should be transformed into a Delta32 targeting
229fe6060f1SDimitry Andric   /// the GOT entry for the edge's current target, maintaining the same addend.
230fe6060f1SDimitry Andric   /// A GOT entry for the target should be created if one does not already
231fe6060f1SDimitry Andric   /// exist.
232fe6060f1SDimitry Andric   ///
233fe6060f1SDimitry Andric   /// Edges of this kind are usually handled by a GOT builder pass inserted by
234fe6060f1SDimitry Andric   /// default.
235fe6060f1SDimitry Andric   ///
236fe6060f1SDimitry Andric   /// Fixup expression:
237fe6060f1SDimitry Andric   ///   NONE
238fe6060f1SDimitry Andric   ///
239fe6060f1SDimitry Andric   /// Errors:
240fe6060f1SDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
241fe6060f1SDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase.
242fe6060f1SDimitry Andric   ///
243fe6060f1SDimitry Andric   RequestGOTAndTransformToDelta32,
244fe6060f1SDimitry Andric 
245349cc55cSDimitry Andric   /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
246349cc55cSDimitry Andric   /// entry for the original target.
247349cc55cSDimitry Andric   ///
248349cc55cSDimitry Andric   /// Indicates that this edge should be transformed into a Delta64 targeting
249349cc55cSDimitry Andric   /// the GOT entry for the edge's current target, maintaining the same addend.
250349cc55cSDimitry Andric   /// A GOT entry for the target should be created if one does not already
251349cc55cSDimitry Andric   /// exist.
252349cc55cSDimitry Andric   ///
253349cc55cSDimitry Andric   /// Edges of this kind are usually handled by a GOT builder pass inserted by
254349cc55cSDimitry Andric   /// default.
255349cc55cSDimitry Andric   ///
256349cc55cSDimitry Andric   /// Fixup expression:
257349cc55cSDimitry Andric   ///   NONE
258349cc55cSDimitry Andric   ///
259349cc55cSDimitry Andric   /// Errors:
260349cc55cSDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
261349cc55cSDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase.
262349cc55cSDimitry Andric   ///
263349cc55cSDimitry Andric   RequestGOTAndTransformToDelta64,
264349cc55cSDimitry Andric 
265349cc55cSDimitry Andric   /// A GOT entry offset within GOT getter/constructor, transformed to
266349cc55cSDimitry Andric   /// Delta64FromGOT
267349cc55cSDimitry Andric   /// pointing at the GOT entry for the original target
268349cc55cSDimitry Andric   ///
269349cc55cSDimitry Andric   /// Indicates that this edge should be transformed into a Delta64FromGOT
270349cc55cSDimitry Andric   /// targeting
271349cc55cSDimitry Andric   /// the GOT entry for the edge's current target, maintaining the same addend.
272349cc55cSDimitry Andric   /// A GOT entry for the target should be created if one does not already
273349cc55cSDimitry Andric   /// exist.
274349cc55cSDimitry Andric   ///
275349cc55cSDimitry Andric   /// Edges of this kind are usually handled by a GOT builder pass inserted by
276349cc55cSDimitry Andric   /// default
277349cc55cSDimitry Andric   ///
278349cc55cSDimitry Andric   /// Fixup expression:
279349cc55cSDimitry Andric   ///   NONE
280349cc55cSDimitry Andric   ///
281349cc55cSDimitry Andric   /// Errors:
282349cc55cSDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
283349cc55cSDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase
284349cc55cSDimitry Andric   RequestGOTAndTransformToDelta64FromGOT,
285349cc55cSDimitry Andric 
286349cc55cSDimitry Andric   /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
287349cc55cSDimitry Andric   /// in-range of the fixup
288349cc55cSDimitry Andric   ///
289349cc55cSDimitry Andric   /// TODO: Explain the optimization
290349cc55cSDimitry Andric   ///
291349cc55cSDimitry Andric   /// Fixup expression
292349cc55cSDimitry Andric   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
293349cc55cSDimitry Andric   ///
294349cc55cSDimitry Andric   /// Errors:
295349cc55cSDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
296349cc55cSDimitry Andric   ///     an out-of-range error will be returned.
297349cc55cSDimitry Andric   //
298349cc55cSDimitry Andric   PCRel32GOTLoadRelaxable,
299349cc55cSDimitry Andric 
300349cc55cSDimitry Andric   /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
301fe6060f1SDimitry Andric   /// is in-range of the fixup.
302fe6060f1SDimitry Andric   ///
303fe6060f1SDimitry Andric   /// If the GOT entry target is in-range of the fixup then the load from the
304fe6060f1SDimitry Andric   /// GOT may be replaced with a direct memory address calculation.
305fe6060f1SDimitry Andric   ///
306fe6060f1SDimitry Andric   /// Fixup expression:
307fe6060f1SDimitry Andric   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
308fe6060f1SDimitry Andric   ///
309fe6060f1SDimitry Andric   /// Errors:
310fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
311fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
312fe6060f1SDimitry Andric   ///
313349cc55cSDimitry Andric   PCRel32GOTLoadREXRelaxable,
314fe6060f1SDimitry Andric 
315349cc55cSDimitry Andric   /// A GOT entry getter/constructor, transformed to
316349cc55cSDimitry Andric   /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
317349cc55cSDimitry Andric   /// target.
318fe6060f1SDimitry Andric   ///
319349cc55cSDimitry Andric   /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
320349cc55cSDimitry Andric   /// targeting the GOT entry for the edge's current target, maintaining the
321349cc55cSDimitry Andric   /// same addend. A GOT entry for the target should be created if one does not
322349cc55cSDimitry Andric   /// already exist.
323fe6060f1SDimitry Andric   ///
324349cc55cSDimitry Andric   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
325349cc55cSDimitry Andric   /// default.
326349cc55cSDimitry Andric   ///
327349cc55cSDimitry Andric   /// Fixup expression:
328349cc55cSDimitry Andric   ///   NONE
329349cc55cSDimitry Andric   ///
330349cc55cSDimitry Andric   /// Errors:
331349cc55cSDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
332349cc55cSDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase.
333349cc55cSDimitry Andric   ///
334349cc55cSDimitry Andric   RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable,
335349cc55cSDimitry Andric 
336349cc55cSDimitry Andric   /// A GOT entry getter/constructor, transformed to
337349cc55cSDimitry Andric   /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
338349cc55cSDimitry Andric   /// target.
339349cc55cSDimitry Andric   ///
340349cc55cSDimitry Andric   /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
341349cc55cSDimitry Andric   /// targeting the GOT entry for the edge's current target, maintaining the
342349cc55cSDimitry Andric   /// same addend. A GOT entry for the target should be created if one does not
343349cc55cSDimitry Andric   /// already exist.
344349cc55cSDimitry Andric   ///
345349cc55cSDimitry Andric   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
346fe6060f1SDimitry Andric   /// default.
347fe6060f1SDimitry Andric   ///
348fe6060f1SDimitry Andric   /// Fixup expression:
349fe6060f1SDimitry Andric   ///   NONE
350fe6060f1SDimitry Andric   ///
351fe6060f1SDimitry Andric   /// Errors:
352fe6060f1SDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
353fe6060f1SDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase.
354fe6060f1SDimitry Andric   ///
355fe6060f1SDimitry Andric   RequestGOTAndTransformToPCRel32GOTLoadRelaxable,
356fe6060f1SDimitry Andric 
357349cc55cSDimitry Andric   /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
358fe6060f1SDimitry Andric   /// relaxable if the TLVP entry target is in-range of the fixup.
359fe6060f1SDimitry Andric   ///
360349cc55cSDimitry Andric   /// If the TLVP entry target is in-range of the fixup then the load from the
361fe6060f1SDimitry Andric   /// TLVP may be replaced with a direct memory address calculation.
362fe6060f1SDimitry Andric   ///
363fe6060f1SDimitry Andric   /// The target of this edge must be a thread local variable entry of the form
364fe6060f1SDimitry Andric   ///   .quad <tlv getter thunk>
365fe6060f1SDimitry Andric   ///   .quad <tlv key>
366fe6060f1SDimitry Andric   ///   .quad <tlv initializer>
367fe6060f1SDimitry Andric   ///
368fe6060f1SDimitry Andric   /// Fixup expression:
369fe6060f1SDimitry Andric   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
370fe6060f1SDimitry Andric   ///
371fe6060f1SDimitry Andric   /// Errors:
372fe6060f1SDimitry Andric   ///   - The result of the fixup expression must fit into an int32, otherwise
373fe6060f1SDimitry Andric   ///     an out-of-range error will be returned.
374fe6060f1SDimitry Andric   ///   - The target must be either external, or a TLV entry of the required
375fe6060f1SDimitry Andric   ///     form, otherwise a malformed TLV entry error will be returned.
376fe6060f1SDimitry Andric   ///
377349cc55cSDimitry Andric   PCRel32TLVPLoadREXRelaxable,
378349cc55cSDimitry Andric 
379349cc55cSDimitry Andric   /// TODO: Explain the generic edge kind
380349cc55cSDimitry Andric   RequestTLSDescInGOTAndTransformToDelta32,
381fe6060f1SDimitry Andric 
382fe6060f1SDimitry Andric   /// A TLVP entry getter/constructor, transformed to
383349cc55cSDimitry Andric   /// Delta32ToTLVPLoadREXRelaxable.
384fe6060f1SDimitry Andric   ///
385fe6060f1SDimitry Andric   /// Indicates that this edge should be transformed into a
386349cc55cSDimitry Andric   /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
387349cc55cSDimitry Andric   /// current target. A TLVP entry for the target should be created if one does
388349cc55cSDimitry Andric   /// not already exist.
389fe6060f1SDimitry Andric   ///
390fe6060f1SDimitry Andric   /// Fixup expression:
391fe6060f1SDimitry Andric   ///   NONE
392fe6060f1SDimitry Andric   ///
393fe6060f1SDimitry Andric   /// Errors:
394fe6060f1SDimitry Andric   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
395fe6060f1SDimitry Andric   ///     phase will result in an assert/unreachable during the fixup phase.
396fe6060f1SDimitry Andric   ///
397972a253aSDimitry Andric   RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable,
398972a253aSDimitry Andric   // First platform specific relocation.
399972a253aSDimitry Andric   FirstPlatformRelocation
400fe6060f1SDimitry Andric };
401fe6060f1SDimitry Andric 
402fe6060f1SDimitry Andric /// Returns a string name for the given x86-64 edge. For debugging purposes
403fe6060f1SDimitry Andric /// only.
404fe6060f1SDimitry Andric const char *getEdgeKindName(Edge::Kind K);
405fe6060f1SDimitry Andric 
406fe6060f1SDimitry Andric /// Apply fixup expression for edge to block content.
applyFixup(LinkGraph & G,Block & B,const Edge & E,const Symbol * GOTSymbol)407349cc55cSDimitry Andric inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
408349cc55cSDimitry Andric                         const Symbol *GOTSymbol) {
409fe6060f1SDimitry Andric   using namespace support;
410fe6060f1SDimitry Andric 
411fe6060f1SDimitry Andric   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
412fe6060f1SDimitry Andric   char *FixupPtr = BlockWorkingMem + E.getOffset();
41304eeddc0SDimitry Andric   auto FixupAddress = B.getAddress() + E.getOffset();
414fe6060f1SDimitry Andric 
415fe6060f1SDimitry Andric   switch (E.getKind()) {
416fe6060f1SDimitry Andric 
417fe6060f1SDimitry Andric   case Pointer64: {
41804eeddc0SDimitry Andric     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
419fe6060f1SDimitry Andric     *(ulittle64_t *)FixupPtr = Value;
420fe6060f1SDimitry Andric     break;
421fe6060f1SDimitry Andric   }
422fe6060f1SDimitry Andric 
423fe6060f1SDimitry Andric   case Pointer32: {
42404eeddc0SDimitry Andric     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
42506c3fb27SDimitry Andric     if (LLVM_LIKELY(isUInt<32>(Value)))
426fe6060f1SDimitry Andric       *(ulittle32_t *)FixupPtr = Value;
427fe6060f1SDimitry Andric     else
428fe6060f1SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
429fe6060f1SDimitry Andric     break;
430fe6060f1SDimitry Andric   }
431349cc55cSDimitry Andric   case Pointer32Signed: {
43204eeddc0SDimitry Andric     int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
43306c3fb27SDimitry Andric     if (LLVM_LIKELY(isInt<32>(Value)))
434349cc55cSDimitry Andric       *(little32_t *)FixupPtr = Value;
435349cc55cSDimitry Andric     else
436349cc55cSDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
437349cc55cSDimitry Andric     break;
438349cc55cSDimitry Andric   }
439fe6060f1SDimitry Andric 
440bdd1243dSDimitry Andric   case Pointer16: {
441bdd1243dSDimitry Andric     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
442bdd1243dSDimitry Andric     if (LLVM_LIKELY(isUInt<16>(Value)))
443bdd1243dSDimitry Andric       *(ulittle16_t *)FixupPtr = Value;
444bdd1243dSDimitry Andric     else
445bdd1243dSDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
446bdd1243dSDimitry Andric     break;
447bdd1243dSDimitry Andric   }
448bdd1243dSDimitry Andric 
44906c3fb27SDimitry Andric   case Pointer8: {
45006c3fb27SDimitry Andric     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
45106c3fb27SDimitry Andric     if (LLVM_LIKELY(isUInt<8>(Value)))
45206c3fb27SDimitry Andric       *(uint8_t *)FixupPtr = Value;
45306c3fb27SDimitry Andric     else
45406c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
45506c3fb27SDimitry Andric     break;
45606c3fb27SDimitry Andric   }
45706c3fb27SDimitry Andric 
458972a253aSDimitry Andric   case PCRel32:
459fe6060f1SDimitry Andric   case BranchPCRel32:
460fe6060f1SDimitry Andric   case BranchPCRel32ToPtrJumpStub:
461349cc55cSDimitry Andric   case BranchPCRel32ToPtrJumpStubBypassable:
462fe6060f1SDimitry Andric   case PCRel32GOTLoadRelaxable:
463349cc55cSDimitry Andric   case PCRel32GOTLoadREXRelaxable:
464349cc55cSDimitry Andric   case PCRel32TLVPLoadREXRelaxable: {
465fe6060f1SDimitry Andric     int64_t Value =
466fe6060f1SDimitry Andric         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
46706c3fb27SDimitry Andric     if (LLVM_LIKELY(isInt<32>(Value)))
468fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = Value;
469fe6060f1SDimitry Andric     else
470fe6060f1SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
471fe6060f1SDimitry Andric     break;
472fe6060f1SDimitry Andric   }
473fe6060f1SDimitry Andric 
474fe6060f1SDimitry Andric   case Delta64: {
475fe6060f1SDimitry Andric     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
476fe6060f1SDimitry Andric     *(little64_t *)FixupPtr = Value;
477fe6060f1SDimitry Andric     break;
478fe6060f1SDimitry Andric   }
479fe6060f1SDimitry Andric 
480fe6060f1SDimitry Andric   case Delta32: {
481fe6060f1SDimitry Andric     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
48206c3fb27SDimitry Andric     if (LLVM_LIKELY(isInt<32>(Value)))
483fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = Value;
484fe6060f1SDimitry Andric     else
485fe6060f1SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
486fe6060f1SDimitry Andric     break;
487fe6060f1SDimitry Andric   }
488fe6060f1SDimitry Andric 
489*0fca6ea1SDimitry Andric   case Delta8: {
490*0fca6ea1SDimitry Andric     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
491*0fca6ea1SDimitry Andric     if (LLVM_LIKELY(isInt<8>(Value)))
492*0fca6ea1SDimitry Andric       *FixupPtr = Value;
493*0fca6ea1SDimitry Andric     else
494*0fca6ea1SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
495*0fca6ea1SDimitry Andric     break;
496*0fca6ea1SDimitry Andric   }
497*0fca6ea1SDimitry Andric 
498fe6060f1SDimitry Andric   case NegDelta64: {
499fe6060f1SDimitry Andric     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
500fe6060f1SDimitry Andric     *(little64_t *)FixupPtr = Value;
501fe6060f1SDimitry Andric     break;
502fe6060f1SDimitry Andric   }
503fe6060f1SDimitry Andric 
504fe6060f1SDimitry Andric   case NegDelta32: {
505fe6060f1SDimitry Andric     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
50606c3fb27SDimitry Andric     if (LLVM_LIKELY(isInt<32>(Value)))
507fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = Value;
508fe6060f1SDimitry Andric     else
509fe6060f1SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
510fe6060f1SDimitry Andric     break;
511fe6060f1SDimitry Andric   }
512349cc55cSDimitry Andric   case Delta64FromGOT: {
513349cc55cSDimitry Andric     assert(GOTSymbol && "No GOT section symbol");
514349cc55cSDimitry Andric     int64_t Value =
515349cc55cSDimitry Andric         E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
516349cc55cSDimitry Andric     *(little64_t *)FixupPtr = Value;
517349cc55cSDimitry Andric     break;
518349cc55cSDimitry Andric   }
519fe6060f1SDimitry Andric 
52081ad6265SDimitry Andric   default:
52181ad6265SDimitry Andric     return make_error<JITLinkError>(
52281ad6265SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
52381ad6265SDimitry Andric         " unsupported edge kind " + getEdgeKindName(E.getKind()));
524fe6060f1SDimitry Andric   }
525fe6060f1SDimitry Andric 
526fe6060f1SDimitry Andric   return Error::success();
527fe6060f1SDimitry Andric }
528fe6060f1SDimitry Andric 
529fe6060f1SDimitry Andric /// x86_64 pointer size.
530fe6060f1SDimitry Andric constexpr uint64_t PointerSize = 8;
531fe6060f1SDimitry Andric 
532fe6060f1SDimitry Andric /// x86-64 null pointer content.
533fe6060f1SDimitry Andric extern const char NullPointerContent[PointerSize];
534fe6060f1SDimitry Andric 
535fe6060f1SDimitry Andric /// x86-64 pointer jump stub content.
536fe6060f1SDimitry Andric ///
537fe6060f1SDimitry Andric /// Contains the instruction sequence for an indirect jump via an in-memory
538fe6060f1SDimitry Andric /// pointer:
539fe6060f1SDimitry Andric ///   jmpq *ptr(%rip)
540fe6060f1SDimitry Andric extern const char PointerJumpStubContent[6];
541fe6060f1SDimitry Andric 
542fe6060f1SDimitry Andric /// Creates a new pointer block in the given section and returns an anonymous
543fe6060f1SDimitry Andric /// symbol pointing to it.
544fe6060f1SDimitry Andric ///
545fe6060f1SDimitry Andric /// If InitialTarget is given then an Pointer64 relocation will be added to the
546fe6060f1SDimitry Andric /// block pointing at InitialTarget.
547fe6060f1SDimitry Andric ///
548fe6060f1SDimitry Andric /// The pointer block will have the following default values:
549fe6060f1SDimitry Andric ///   alignment: 64-bit
550fe6060f1SDimitry Andric ///   alignment-offset: 0
551fe6060f1SDimitry Andric ///   address: highest allowable (~7U)
552fe6060f1SDimitry Andric inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
553fe6060f1SDimitry Andric                                       Symbol *InitialTarget = nullptr,
554fe6060f1SDimitry Andric                                       uint64_t InitialAddend = 0) {
55504eeddc0SDimitry Andric   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
55604eeddc0SDimitry Andric                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
557fe6060f1SDimitry Andric   if (InitialTarget)
558fe6060f1SDimitry Andric     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
559fe6060f1SDimitry Andric   return G.addAnonymousSymbol(B, 0, 8, false, false);
560fe6060f1SDimitry Andric }
561fe6060f1SDimitry Andric 
562fe6060f1SDimitry Andric /// Create a jump stub block that jumps via the pointer at the given symbol.
563fe6060f1SDimitry Andric ///
564fe6060f1SDimitry Andric /// The stub block will have the following default values:
565fe6060f1SDimitry Andric ///   alignment: 8-bit
566fe6060f1SDimitry Andric ///   alignment-offset: 0
567fe6060f1SDimitry Andric ///   address: highest allowable: (~5U)
createPointerJumpStubBlock(LinkGraph & G,Section & StubSection,Symbol & PointerSymbol)568fe6060f1SDimitry Andric inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
569fe6060f1SDimitry Andric                                          Symbol &PointerSymbol) {
57004eeddc0SDimitry Andric   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
57104eeddc0SDimitry Andric                                  orc::ExecutorAddr(~uint64_t(5)), 1, 0);
5725f757f3fSDimitry Andric   B.addEdge(BranchPCRel32, 2, PointerSymbol, 0);
573fe6060f1SDimitry Andric   return B;
574fe6060f1SDimitry Andric }
575fe6060f1SDimitry Andric 
576fe6060f1SDimitry Andric /// Create a jump stub that jumps via the pointer at the given symbol and
577fe6060f1SDimitry Andric /// an anonymous symbol pointing to it. Return the anonymous symbol.
578fe6060f1SDimitry Andric ///
579fe6060f1SDimitry Andric /// The stub block will be created by createPointerJumpStubBlock.
createAnonymousPointerJumpStub(LinkGraph & G,Section & StubSection,Symbol & PointerSymbol)580fe6060f1SDimitry Andric inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
581fe6060f1SDimitry Andric                                               Section &StubSection,
582fe6060f1SDimitry Andric                                               Symbol &PointerSymbol) {
583fe6060f1SDimitry Andric   return G.addAnonymousSymbol(
584fe6060f1SDimitry Andric       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
585fe6060f1SDimitry Andric       false);
586fe6060f1SDimitry Andric }
587fe6060f1SDimitry Andric 
588349cc55cSDimitry Andric /// Global Offset Table Builder.
589349cc55cSDimitry Andric class GOTTableManager : public TableManager<GOTTableManager> {
590349cc55cSDimitry Andric public:
getSectionName()591349cc55cSDimitry Andric   static StringRef getSectionName() { return "$__GOT"; }
592349cc55cSDimitry Andric 
visitEdge(LinkGraph & G,Block * B,Edge & E)593349cc55cSDimitry Andric   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
594349cc55cSDimitry Andric     Edge::Kind KindToSet = Edge::Invalid;
595349cc55cSDimitry Andric     switch (E.getKind()) {
596349cc55cSDimitry Andric     case x86_64::Delta64FromGOT: {
597349cc55cSDimitry Andric       // we need to make sure that the GOT section exists, but don't otherwise
598349cc55cSDimitry Andric       // need to fix up this edge
599349cc55cSDimitry Andric       getGOTSection(G);
600349cc55cSDimitry Andric       return false;
601349cc55cSDimitry Andric     }
602349cc55cSDimitry Andric     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
603349cc55cSDimitry Andric       KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
604349cc55cSDimitry Andric       break;
605349cc55cSDimitry Andric     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
606349cc55cSDimitry Andric       KindToSet = x86_64::PCRel32GOTLoadRelaxable;
607349cc55cSDimitry Andric       break;
608349cc55cSDimitry Andric     case x86_64::RequestGOTAndTransformToDelta64:
609349cc55cSDimitry Andric       KindToSet = x86_64::Delta64;
610349cc55cSDimitry Andric       break;
611349cc55cSDimitry Andric     case x86_64::RequestGOTAndTransformToDelta64FromGOT:
612349cc55cSDimitry Andric       KindToSet = x86_64::Delta64FromGOT;
613349cc55cSDimitry Andric       break;
614349cc55cSDimitry Andric     case x86_64::RequestGOTAndTransformToDelta32:
615349cc55cSDimitry Andric       KindToSet = x86_64::Delta32;
616349cc55cSDimitry Andric       break;
617349cc55cSDimitry Andric     default:
618349cc55cSDimitry Andric       return false;
619349cc55cSDimitry Andric     }
620349cc55cSDimitry Andric     assert(KindToSet != Edge::Invalid &&
621349cc55cSDimitry Andric            "Fell through switch, but no new kind to set");
622349cc55cSDimitry Andric     DEBUG_WITH_TYPE("jitlink", {
623349cc55cSDimitry Andric       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
62404eeddc0SDimitry Andric              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
625349cc55cSDimitry Andric              << formatv("{0:x}", E.getOffset()) << ")\n";
626349cc55cSDimitry Andric     });
627349cc55cSDimitry Andric     E.setKind(KindToSet);
628349cc55cSDimitry Andric     E.setTarget(getEntryForTarget(G, E.getTarget()));
629349cc55cSDimitry Andric     return true;
630349cc55cSDimitry Andric   }
631349cc55cSDimitry Andric 
createEntry(LinkGraph & G,Symbol & Target)632349cc55cSDimitry Andric   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
633349cc55cSDimitry Andric     return createAnonymousPointer(G, getGOTSection(G), &Target);
634349cc55cSDimitry Andric   }
635349cc55cSDimitry Andric 
636349cc55cSDimitry Andric private:
getGOTSection(LinkGraph & G)637349cc55cSDimitry Andric   Section &getGOTSection(LinkGraph &G) {
638349cc55cSDimitry Andric     if (!GOTSection)
639bdd1243dSDimitry Andric       GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
640349cc55cSDimitry Andric     return *GOTSection;
641349cc55cSDimitry Andric   }
642349cc55cSDimitry Andric 
643349cc55cSDimitry Andric   Section *GOTSection = nullptr;
644349cc55cSDimitry Andric };
645349cc55cSDimitry Andric 
646349cc55cSDimitry Andric /// Procedure Linkage Table Builder.
647349cc55cSDimitry Andric class PLTTableManager : public TableManager<PLTTableManager> {
648349cc55cSDimitry Andric public:
PLTTableManager(GOTTableManager & GOT)649349cc55cSDimitry Andric   PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
650349cc55cSDimitry Andric 
getSectionName()651349cc55cSDimitry Andric   static StringRef getSectionName() { return "$__STUBS"; }
652349cc55cSDimitry Andric 
visitEdge(LinkGraph & G,Block * B,Edge & E)653349cc55cSDimitry Andric   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
654349cc55cSDimitry Andric     if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
655349cc55cSDimitry Andric       DEBUG_WITH_TYPE("jitlink", {
656349cc55cSDimitry Andric         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
65704eeddc0SDimitry Andric                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
658349cc55cSDimitry Andric                << formatv("{0:x}", E.getOffset()) << ")\n";
659349cc55cSDimitry Andric       });
660349cc55cSDimitry Andric       // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
661349cc55cSDimitry Andric       // be optimized when the target is in-range.
662349cc55cSDimitry Andric       E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
663349cc55cSDimitry Andric       E.setTarget(getEntryForTarget(G, E.getTarget()));
664349cc55cSDimitry Andric       return true;
665349cc55cSDimitry Andric     }
666349cc55cSDimitry Andric     return false;
667349cc55cSDimitry Andric   }
668349cc55cSDimitry Andric 
createEntry(LinkGraph & G,Symbol & Target)669349cc55cSDimitry Andric   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
670349cc55cSDimitry Andric     return createAnonymousPointerJumpStub(G, getStubsSection(G),
671349cc55cSDimitry Andric                                           GOT.getEntryForTarget(G, Target));
672349cc55cSDimitry Andric   }
673349cc55cSDimitry Andric 
674349cc55cSDimitry Andric public:
getStubsSection(LinkGraph & G)675349cc55cSDimitry Andric   Section &getStubsSection(LinkGraph &G) {
676349cc55cSDimitry Andric     if (!PLTSection)
677bdd1243dSDimitry Andric       PLTSection = &G.createSection(getSectionName(),
678bdd1243dSDimitry Andric                                     orc::MemProt::Read | orc::MemProt::Exec);
679349cc55cSDimitry Andric     return *PLTSection;
680349cc55cSDimitry Andric   }
681349cc55cSDimitry Andric 
682349cc55cSDimitry Andric   GOTTableManager &GOT;
683349cc55cSDimitry Andric   Section *PLTSection = nullptr;
684349cc55cSDimitry Andric };
685349cc55cSDimitry Andric 
686349cc55cSDimitry Andric /// Optimize the GOT and Stub relocations if the edge target address is in range
687349cc55cSDimitry Andric /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
688349cc55cSDimitry Andric /// then replace GOT load with lea
689349cc55cSDimitry Andric /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
690349cc55cSDimitry Andric /// in range, replace a indirect jump by plt stub with a direct jump to the
691349cc55cSDimitry Andric /// target
692349cc55cSDimitry Andric Error optimizeGOTAndStubAccesses(LinkGraph &G);
693349cc55cSDimitry Andric 
694fe6060f1SDimitry Andric } // namespace x86_64
695fe6060f1SDimitry Andric } // end namespace jitlink
696fe6060f1SDimitry Andric } // end namespace llvm
697fe6060f1SDimitry Andric 
698fe6060f1SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
699