xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h (revision 2008043f386721d58158e37e0d7e50df8095942d)
1 //===-- x86_64.h - Generic JITLink x86-64 edge kinds, utilities -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Generic utilities for graphs representing x86-64 objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
14 #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
15 
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITLink/TableManager.h"
18 
19 #include <limits>
20 
21 namespace llvm {
22 namespace jitlink {
23 namespace x86_64 {
24 
25 /// Represents x86-64 fixups and other x86-64-specific edge kinds.
26 enum EdgeKind_x86_64 : Edge::Kind {
27 
28   /// A plain 64-bit pointer value relocation.
29   ///
30   /// Fixup expression:
31   ///   Fixup <- Target + Addend : uint64
32   ///
33   Pointer64 = Edge::FirstRelocation,
34 
35   /// A plain 32-bit pointer value relocation.
36   ///
37   /// Fixup expression:
38   ///   Fixup <- Target + Addend : uint32
39   ///
40   /// Errors:
41   ///   - The target must reside in the low 32-bits of the address space,
42   ///     otherwise an out-of-range error will be returned.
43   ///
44   Pointer32,
45 
46   /// A signed 32-bit pointer value relocation
47   ///
48   /// Fixup expression:
49   ///   Fixup <- Target + Addend : int32
50   ///
51   /// Errors:
52   ///   - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of
53   ///   the address space, otherwise an out-of-range error will be returned.
54   Pointer32Signed,
55 
56   /// A plain 16-bit pointer value relocation.
57   ///
58   /// Fixup expression:
59   ///   Fixup <- Target + Addend : uint16
60   ///
61   /// Errors:
62   ///   - The target must reside in the low 16-bits of the address space,
63   ///     otherwise an out-of-range error will be returned.
64   ///
65   Pointer16,
66 
67   /// A 64-bit delta.
68   ///
69   /// Delta from the fixup to the target.
70   ///
71   /// Fixup expression:
72   ///   Fixup <- Target - Fixup + Addend : int64
73   ///
74   Delta64,
75 
76   /// A 32-bit delta.
77   ///
78   /// Delta from the fixup to the target.
79   ///
80   /// Fixup expression:
81   ///   Fixup <- Target - Fixup + Addend : int64
82   ///
83   /// Errors:
84   ///   - The result of the fixup expression must fit into an int32, otherwise
85   ///     an out-of-range error will be returned.
86   ///
87   Delta32,
88 
89   /// A 64-bit negative delta.
90   ///
91   /// Delta from target back to the fixup.
92   ///
93   /// Fixup expression:
94   ///   Fixup <- Fixup - Target + Addend : int64
95   ///
96   NegDelta64,
97 
98   /// A 32-bit negative delta.
99   ///
100   /// Delta from the target back to the fixup.
101   ///
102   /// Fixup expression:
103   ///   Fixup <- Fixup - Target + Addend : int32
104   ///
105   /// Errors:
106   ///   - The result of the fixup expression must fit into an int32, otherwise
107   ///     an out-of-range error will be returned.
108   NegDelta32,
109 
110   /// A 64-bit GOT delta.
111   ///
112   /// Delta from the global offset table to the target
113   ///
114   /// Fixup expression:
115   ///   Fixup <- Target - GOTSymbol + Addend : int64
116   ///
117   /// Errors:
118   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
119   ///     symbol was not been defined.
120   Delta64FromGOT,
121 
122   /// A 32-bit PC-relative branch.
123   ///
124   /// Represents a PC-relative call or branch to a target. This can be used to
125   /// identify, record, and/or patch call sites.
126   ///
127   /// The fixup expression for this kind includes an implicit offset to account
128   /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
129   /// T and addend zero is a call/branch to the start (offset zero) of T.
130   ///
131   /// Fixup expression:
132   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
133   ///
134   /// Errors:
135   ///   - The result of the fixup expression must fit into an int32, otherwise
136   ///     an out-of-range error will be returned.
137   ///
138   BranchPCRel32,
139 
140   /// A 32-bit PC-relative relocation.
141   ///
142   /// Represents a data/control flow instruction using PC-relative addressing
143   /// to a target.
144   ///
145   /// The fixup expression for this kind includes an implicit offset to account
146   /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
147   /// T and addend zero is a call/branch to the start (offset zero) of T.
148   ///
149   /// Fixup expression:
150   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
151   ///
152   /// Errors:
153   ///   - The result of the fixup expression must fit into an int32, otherwise
154   ///     an out-of-range error will be returned.
155   ///
156   PCRel32,
157 
158   /// A 32-bit PC-relative branch to a pointer jump stub.
159   ///
160   /// The target of this relocation should be a pointer jump stub of the form:
161   ///
162   /// \code{.s}
163   ///   .text
164   ///   jmpq *tgtptr(%rip)
165   ///   ; ...
166   ///
167   ///   .data
168   ///   tgtptr:
169   ///     .quad 0
170   /// \endcode
171   ///
172   /// This edge kind has the same fixup expression as BranchPCRel32, but further
173   /// identifies the call/branch as being to a pointer jump stub. For edges of
174   /// this kind the jump stub should not be bypassed (use
175   /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
176   /// target may be recorded to allow manipulation at runtime.
177   ///
178   /// Fixup expression:
179   ///   Fixup <- Target - Fixup + Addend - 4 : int32
180   ///
181   /// Errors:
182   ///   - The result of the fixup expression must fit into an int32, otherwise
183   ///     an out-of-range error will be returned.
184   ///
185   BranchPCRel32ToPtrJumpStub,
186 
187   /// A relaxable version of BranchPCRel32ToPtrJumpStub.
188   ///
189   /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
190   /// but identifies the call/branch as being to a pointer jump stub that may be
191   /// bypassed with a direct jump to the ultimate target if the ultimate target
192   /// is within range of the fixup location.
193   ///
194   /// Fixup expression:
195   ///   Fixup <- Target - Fixup + Addend - 4: int32
196   ///
197   /// Errors:
198   ///   - The result of the fixup expression must fit into an int32, otherwise
199   ///     an out-of-range error will be returned.
200   ///
201   BranchPCRel32ToPtrJumpStubBypassable,
202 
203   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
204   /// entry for the original target.
205   ///
206   /// Indicates that this edge should be transformed into a Delta32 targeting
207   /// the GOT entry for the edge's current target, maintaining the same addend.
208   /// A GOT entry for the target should be created if one does not already
209   /// exist.
210   ///
211   /// Edges of this kind are usually handled by a GOT builder pass inserted by
212   /// default.
213   ///
214   /// Fixup expression:
215   ///   NONE
216   ///
217   /// Errors:
218   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
219   ///     phase will result in an assert/unreachable during the fixup phase.
220   ///
221   RequestGOTAndTransformToDelta32,
222 
223   /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
224   /// entry for the original target.
225   ///
226   /// Indicates that this edge should be transformed into a Delta64 targeting
227   /// the GOT entry for the edge's current target, maintaining the same addend.
228   /// A GOT entry for the target should be created if one does not already
229   /// exist.
230   ///
231   /// Edges of this kind are usually handled by a GOT builder pass inserted by
232   /// default.
233   ///
234   /// Fixup expression:
235   ///   NONE
236   ///
237   /// Errors:
238   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
239   ///     phase will result in an assert/unreachable during the fixup phase.
240   ///
241   RequestGOTAndTransformToDelta64,
242 
243   /// A GOT entry offset within GOT getter/constructor, transformed to
244   /// Delta64FromGOT
245   /// pointing at the GOT entry for the original target
246   ///
247   /// Indicates that this edge should be transformed into a Delta64FromGOT
248   /// targeting
249   /// the GOT entry for the edge's current target, maintaining the same addend.
250   /// A GOT entry for the target should be created if one does not already
251   /// exist.
252   ///
253   /// Edges of this kind are usually handled by a GOT builder pass inserted by
254   /// default
255   ///
256   /// Fixup expression:
257   ///   NONE
258   ///
259   /// Errors:
260   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
261   ///     phase will result in an assert/unreachable during the fixup phase
262   RequestGOTAndTransformToDelta64FromGOT,
263 
264   /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
265   /// in-range of the fixup
266   ///
267   /// TODO: Explain the optimization
268   ///
269   /// Fixup expression
270   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
271   ///
272   /// Errors:
273   ///   - The result of the fixup expression must fit into an int32, otherwise
274   ///     an out-of-range error will be returned.
275   //
276   PCRel32GOTLoadRelaxable,
277 
278   /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
279   /// is in-range of the fixup.
280   ///
281   /// If the GOT entry target is in-range of the fixup then the load from the
282   /// GOT may be replaced with a direct memory address calculation.
283   ///
284   /// Fixup expression:
285   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
286   ///
287   /// Errors:
288   ///   - The result of the fixup expression must fit into an int32, otherwise
289   ///     an out-of-range error will be returned.
290   ///
291   PCRel32GOTLoadREXRelaxable,
292 
293   /// A GOT entry getter/constructor, transformed to
294   /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
295   /// target.
296   ///
297   /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
298   /// targeting the GOT entry for the edge's current target, maintaining the
299   /// same addend. A GOT entry for the target should be created if one does not
300   /// already exist.
301   ///
302   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
303   /// default.
304   ///
305   /// Fixup expression:
306   ///   NONE
307   ///
308   /// Errors:
309   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
310   ///     phase will result in an assert/unreachable during the fixup phase.
311   ///
312   RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable,
313 
314   /// A GOT entry getter/constructor, transformed to
315   /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
316   /// target.
317   ///
318   /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
319   /// targeting the GOT entry for the edge's current target, maintaining the
320   /// same addend. A GOT entry for the target should be created if one does not
321   /// already exist.
322   ///
323   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
324   /// default.
325   ///
326   /// Fixup expression:
327   ///   NONE
328   ///
329   /// Errors:
330   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
331   ///     phase will result in an assert/unreachable during the fixup phase.
332   ///
333   RequestGOTAndTransformToPCRel32GOTLoadRelaxable,
334 
335   /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
336   /// relaxable if the TLVP entry target is in-range of the fixup.
337   ///
338   /// If the TLVP entry target is in-range of the fixup then the load from the
339   /// TLVP may be replaced with a direct memory address calculation.
340   ///
341   /// The target of this edge must be a thread local variable entry of the form
342   ///   .quad <tlv getter thunk>
343   ///   .quad <tlv key>
344   ///   .quad <tlv initializer>
345   ///
346   /// Fixup expression:
347   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
348   ///
349   /// Errors:
350   ///   - The result of the fixup expression must fit into an int32, otherwise
351   ///     an out-of-range error will be returned.
352   ///   - The target must be either external, or a TLV entry of the required
353   ///     form, otherwise a malformed TLV entry error will be returned.
354   ///
355   PCRel32TLVPLoadREXRelaxable,
356 
357   /// TODO: Explain the generic edge kind
358   RequestTLSDescInGOTAndTransformToDelta32,
359 
360   /// A TLVP entry getter/constructor, transformed to
361   /// Delta32ToTLVPLoadREXRelaxable.
362   ///
363   /// Indicates that this edge should be transformed into a
364   /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
365   /// current target. A TLVP entry for the target should be created if one does
366   /// not already exist.
367   ///
368   /// Fixup expression:
369   ///   NONE
370   ///
371   /// Errors:
372   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
373   ///     phase will result in an assert/unreachable during the fixup phase.
374   ///
375   RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable,
376   // First platform specific relocation.
377   FirstPlatformRelocation
378 };
379 
380 /// Returns a string name for the given x86-64 edge. For debugging purposes
381 /// only.
382 const char *getEdgeKindName(Edge::Kind K);
383 
384 /// Returns true if the given uint64_t value is in range for a uint32_t.
385 inline bool isInRangeForImmU32(uint64_t Value) {
386   return Value <= std::numeric_limits<uint32_t>::max();
387 }
388 
389 /// Returns true if the given int64_t value is in range for an int32_t.
390 inline bool isInRangeForImmS32(int64_t Value) {
391   return (Value >= std::numeric_limits<int32_t>::min() &&
392           Value <= std::numeric_limits<int32_t>::max());
393 }
394 
395 /// Apply fixup expression for edge to block content.
396 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
397                         const Symbol *GOTSymbol) {
398   using namespace support;
399 
400   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
401   char *FixupPtr = BlockWorkingMem + E.getOffset();
402   auto FixupAddress = B.getAddress() + E.getOffset();
403 
404   switch (E.getKind()) {
405 
406   case Pointer64: {
407     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
408     *(ulittle64_t *)FixupPtr = Value;
409     break;
410   }
411 
412   case Pointer32: {
413     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
414     if (LLVM_LIKELY(isInRangeForImmU32(Value)))
415       *(ulittle32_t *)FixupPtr = Value;
416     else
417       return makeTargetOutOfRangeError(G, B, E);
418     break;
419   }
420   case Pointer32Signed: {
421     int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
422     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
423       *(little32_t *)FixupPtr = Value;
424     else
425       return makeTargetOutOfRangeError(G, B, E);
426     break;
427   }
428 
429   case Pointer16: {
430     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
431     if (LLVM_LIKELY(isUInt<16>(Value)))
432       *(ulittle16_t *)FixupPtr = Value;
433     else
434       return makeTargetOutOfRangeError(G, B, E);
435     break;
436   }
437 
438   case PCRel32:
439   case BranchPCRel32:
440   case BranchPCRel32ToPtrJumpStub:
441   case BranchPCRel32ToPtrJumpStubBypassable:
442   case PCRel32GOTLoadRelaxable:
443   case PCRel32GOTLoadREXRelaxable:
444   case PCRel32TLVPLoadREXRelaxable: {
445     int64_t Value =
446         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
447     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
448       *(little32_t *)FixupPtr = Value;
449     else
450       return makeTargetOutOfRangeError(G, B, E);
451     break;
452   }
453 
454   case Delta64: {
455     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
456     *(little64_t *)FixupPtr = Value;
457     break;
458   }
459 
460   case Delta32: {
461     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
462     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
463       *(little32_t *)FixupPtr = Value;
464     else
465       return makeTargetOutOfRangeError(G, B, E);
466     break;
467   }
468 
469   case NegDelta64: {
470     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
471     *(little64_t *)FixupPtr = Value;
472     break;
473   }
474 
475   case NegDelta32: {
476     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
477     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
478       *(little32_t *)FixupPtr = Value;
479     else
480       return makeTargetOutOfRangeError(G, B, E);
481     break;
482   }
483   case Delta64FromGOT: {
484     assert(GOTSymbol && "No GOT section symbol");
485     int64_t Value =
486         E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
487     *(little64_t *)FixupPtr = Value;
488     break;
489   }
490 
491   default:
492     return make_error<JITLinkError>(
493         "In graph " + G.getName() + ", section " + B.getSection().getName() +
494         "unsupported edge kind" + getEdgeKindName(E.getKind()));
495   }
496 
497   return Error::success();
498 }
499 
500 /// x86_64 pointer size.
501 constexpr uint64_t PointerSize = 8;
502 
503 /// x86-64 null pointer content.
504 extern const char NullPointerContent[PointerSize];
505 
506 /// x86-64 pointer jump stub content.
507 ///
508 /// Contains the instruction sequence for an indirect jump via an in-memory
509 /// pointer:
510 ///   jmpq *ptr(%rip)
511 extern const char PointerJumpStubContent[6];
512 
513 /// Creates a new pointer block in the given section and returns an anonymous
514 /// symbol pointing to it.
515 ///
516 /// If InitialTarget is given then an Pointer64 relocation will be added to the
517 /// block pointing at InitialTarget.
518 ///
519 /// The pointer block will have the following default values:
520 ///   alignment: 64-bit
521 ///   alignment-offset: 0
522 ///   address: highest allowable (~7U)
523 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
524                                       Symbol *InitialTarget = nullptr,
525                                       uint64_t InitialAddend = 0) {
526   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
527                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
528   if (InitialTarget)
529     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
530   return G.addAnonymousSymbol(B, 0, 8, false, false);
531 }
532 
533 /// Create a jump stub block that jumps via the pointer at the given symbol.
534 ///
535 /// The stub block will have the following default values:
536 ///   alignment: 8-bit
537 ///   alignment-offset: 0
538 ///   address: highest allowable: (~5U)
539 inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
540                                          Symbol &PointerSymbol) {
541   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
542                                  orc::ExecutorAddr(~uint64_t(5)), 1, 0);
543   B.addEdge(Delta32, 2, PointerSymbol, -4);
544   return B;
545 }
546 
547 /// Create a jump stub that jumps via the pointer at the given symbol and
548 /// an anonymous symbol pointing to it. Return the anonymous symbol.
549 ///
550 /// The stub block will be created by createPointerJumpStubBlock.
551 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
552                                               Section &StubSection,
553                                               Symbol &PointerSymbol) {
554   return G.addAnonymousSymbol(
555       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
556       false);
557 }
558 
559 /// Global Offset Table Builder.
560 class GOTTableManager : public TableManager<GOTTableManager> {
561 public:
562   static StringRef getSectionName() { return "$__GOT"; }
563 
564   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
565     Edge::Kind KindToSet = Edge::Invalid;
566     switch (E.getKind()) {
567     case x86_64::Delta64FromGOT: {
568       // we need to make sure that the GOT section exists, but don't otherwise
569       // need to fix up this edge
570       getGOTSection(G);
571       return false;
572     }
573     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
574       KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
575       break;
576     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
577       KindToSet = x86_64::PCRel32GOTLoadRelaxable;
578       break;
579     case x86_64::RequestGOTAndTransformToDelta64:
580       KindToSet = x86_64::Delta64;
581       break;
582     case x86_64::RequestGOTAndTransformToDelta64FromGOT:
583       KindToSet = x86_64::Delta64FromGOT;
584       break;
585     case x86_64::RequestGOTAndTransformToDelta32:
586       KindToSet = x86_64::Delta32;
587       break;
588     default:
589       return false;
590     }
591     assert(KindToSet != Edge::Invalid &&
592            "Fell through switch, but no new kind to set");
593     DEBUG_WITH_TYPE("jitlink", {
594       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
595              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
596              << formatv("{0:x}", E.getOffset()) << ")\n";
597     });
598     E.setKind(KindToSet);
599     E.setTarget(getEntryForTarget(G, E.getTarget()));
600     return true;
601   }
602 
603   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
604     return createAnonymousPointer(G, getGOTSection(G), &Target);
605   }
606 
607 private:
608   Section &getGOTSection(LinkGraph &G) {
609     if (!GOTSection)
610       GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
611     return *GOTSection;
612   }
613 
614   Section *GOTSection = nullptr;
615 };
616 
617 /// Procedure Linkage Table Builder.
618 class PLTTableManager : public TableManager<PLTTableManager> {
619 public:
620   PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
621 
622   static StringRef getSectionName() { return "$__STUBS"; }
623 
624   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
625     if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
626       DEBUG_WITH_TYPE("jitlink", {
627         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
628                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
629                << formatv("{0:x}", E.getOffset()) << ")\n";
630       });
631       // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
632       // be optimized when the target is in-range.
633       E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
634       E.setTarget(getEntryForTarget(G, E.getTarget()));
635       return true;
636     }
637     return false;
638   }
639 
640   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
641     return createAnonymousPointerJumpStub(G, getStubsSection(G),
642                                           GOT.getEntryForTarget(G, Target));
643   }
644 
645 public:
646   Section &getStubsSection(LinkGraph &G) {
647     if (!PLTSection)
648       PLTSection = &G.createSection(getSectionName(),
649                                     orc::MemProt::Read | orc::MemProt::Exec);
650     return *PLTSection;
651   }
652 
653   GOTTableManager &GOT;
654   Section *PLTSection = nullptr;
655 };
656 
657 /// Optimize the GOT and Stub relocations if the edge target address is in range
658 /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
659 /// then replace GOT load with lea
660 /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
661 /// in range, replace a indirect jump by plt stub with a direct jump to the
662 /// target
663 Error optimizeGOTAndStubAccesses(LinkGraph &G);
664 
665 } // namespace x86_64
666 } // end namespace jitlink
667 } // end namespace llvm
668 
669 #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
670