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