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