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