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