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