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