LLVM  14.0.0git
x86_64.h
Go to the documentation of this file.
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 
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.
27 
28  /// A plain 64-bit pointer value relocation.
29  ///
30  /// Fixup expression:
31  /// Fixup <- Target + Addend : uint64
32  ///
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  ///
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.
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  ///
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  ///
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  ///
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.
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.
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  ///
128 
129  /// A 32-bit PC-relative branch to a pointer jump stub.
130  ///
131  /// The target of this relocation should be a pointer jump stub of the form:
132  ///
133  /// \code{.s}
134  /// .text
135  /// jmpq *tgtptr(%rip)
136  /// ; ...
137  ///
138  /// .data
139  /// tgtptr:
140  /// .quad 0
141  /// \endcode
142  ///
143  /// This edge kind has the same fixup expression as BranchPCRel32, but further
144  /// identifies the call/branch as being to a pointer jump stub. For edges of
145  /// this kind the jump stub should not be bypassed (use
146  /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
147  /// target may be recorded to allow manipulation at runtime.
148  ///
149  /// Fixup expression:
150  /// Fixup <- Target - Fixup + Addend - 4 : int32
151  ///
152  /// Errors:
153  /// - The result of the fixup expression must fit into an int32, otherwise
154  /// an out-of-range error will be returned.
155  ///
157 
158  /// A relaxable version of BranchPCRel32ToPtrJumpStub.
159  ///
160  /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
161  /// but identifies the call/branch as being to a pointer jump stub that may be
162  /// bypassed with a direct jump to the ultimate target if the ultimate target
163  /// is within range of the fixup location.
164  ///
165  /// Fixup expression:
166  /// Fixup <- Target - Fixup + Addend - 4: int32
167  ///
168  /// Errors:
169  /// - The result of the fixup expression must fit into an int32, otherwise
170  /// an out-of-range error will be returned.
171  ///
173 
174  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
175  /// entry for the original target.
176  ///
177  /// Indicates that this edge should be transformed into a Delta32 targeting
178  /// the GOT entry for the edge's current target, maintaining the same addend.
179  /// A GOT entry for the target should be created if one does not already
180  /// exist.
181  ///
182  /// Edges of this kind are usually handled by a GOT builder pass inserted by
183  /// default.
184  ///
185  /// Fixup expression:
186  /// NONE
187  ///
188  /// Errors:
189  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
190  /// phase will result in an assert/unreachable during the fixup phase.
191  ///
193 
194  /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
195  /// entry for the original target.
196  ///
197  /// Indicates that this edge should be transformed into a Delta64 targeting
198  /// the GOT entry for the edge's current target, maintaining the same addend.
199  /// A GOT entry for the target should be created if one does not already
200  /// exist.
201  ///
202  /// Edges of this kind are usually handled by a GOT builder pass inserted by
203  /// default.
204  ///
205  /// Fixup expression:
206  /// NONE
207  ///
208  /// Errors:
209  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
210  /// phase will result in an assert/unreachable during the fixup phase.
211  ///
213 
214  /// A GOT entry offset within GOT getter/constructor, transformed to
215  /// Delta64FromGOT
216  /// pointing at the GOT entry for the original target
217  ///
218  /// Indicates that this edge should be transformed into a Delta64FromGOT
219  /// targeting
220  /// the GOT entry for the edge's current target, maintaining the same addend.
221  /// A GOT entry for the target should be created if one does not already
222  /// exist.
223  ///
224  /// Edges of this kind are usually handled by a GOT builder pass inserted by
225  /// default
226  ///
227  /// Fixup expression:
228  /// NONE
229  ///
230  /// Errors:
231  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
232  /// phase will result in an assert/unreachable during the fixup phase
234 
235  /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
236  /// in-range of the fixup
237  ///
238  /// TODO: Explain the optimization
239  ///
240  /// Fixup expression
241  /// Fixup <- Target - (Fixup + 4) + Addend : int32
242  ///
243  /// Errors:
244  /// - The result of the fixup expression must fit into an int32, otherwise
245  /// an out-of-range error will be returned.
246  //
248 
249  /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
250  /// is in-range of the fixup.
251  ///
252  /// If the GOT entry target is in-range of the fixup then the load from the
253  /// GOT may be replaced with a direct memory address calculation.
254  ///
255  /// Fixup expression:
256  /// Fixup <- Target - (Fixup + 4) + Addend : int32
257  ///
258  /// Errors:
259  /// - The result of the fixup expression must fit into an int32, otherwise
260  /// an out-of-range error will be returned.
261  ///
263 
264  /// A GOT entry getter/constructor, transformed to
265  /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
266  /// target.
267  ///
268  /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
269  /// targeting the GOT entry for the edge's current target, maintaining the
270  /// same addend. A GOT entry for the target should be created if one does not
271  /// already exist.
272  ///
273  /// Edges of this kind are usually lowered by a GOT builder pass inserted by
274  /// default.
275  ///
276  /// Fixup expression:
277  /// NONE
278  ///
279  /// Errors:
280  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
281  /// phase will result in an assert/unreachable during the fixup phase.
282  ///
284 
285  /// A GOT entry getter/constructor, transformed to
286  /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
287  /// target.
288  ///
289  /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
290  /// targeting the GOT entry for the edge's current target, maintaining the
291  /// same addend. A GOT entry for the target should be created if one does not
292  /// already exist.
293  ///
294  /// Edges of this kind are usually lowered by a GOT builder pass inserted by
295  /// default.
296  ///
297  /// Fixup expression:
298  /// NONE
299  ///
300  /// Errors:
301  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
302  /// phase will result in an assert/unreachable during the fixup phase.
303  ///
305 
306  /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
307  /// relaxable if the TLVP entry target is in-range of the fixup.
308  ///
309  /// If the TLVP entry target is in-range of the fixup then the load from the
310  /// TLVP may be replaced with a direct memory address calculation.
311  ///
312  /// The target of this edge must be a thread local variable entry of the form
313  /// .quad <tlv getter thunk>
314  /// .quad <tlv key>
315  /// .quad <tlv initializer>
316  ///
317  /// Fixup expression:
318  /// Fixup <- Target - (Fixup + 4) + Addend : int32
319  ///
320  /// Errors:
321  /// - The result of the fixup expression must fit into an int32, otherwise
322  /// an out-of-range error will be returned.
323  /// - The target must be either external, or a TLV entry of the required
324  /// form, otherwise a malformed TLV entry error will be returned.
325  ///
327 
328  /// TODO: Explain the generic edge kind
330 
331  /// A TLVP entry getter/constructor, transformed to
332  /// Delta32ToTLVPLoadREXRelaxable.
333  ///
334  /// Indicates that this edge should be transformed into a
335  /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
336  /// current target. A TLVP entry for the target should be created if one does
337  /// not already exist.
338  ///
339  /// Fixup expression:
340  /// NONE
341  ///
342  /// Errors:
343  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
344  /// phase will result in an assert/unreachable during the fixup phase.
345  ///
347 };
348 
349 /// Returns a string name for the given x86-64 edge. For debugging purposes
350 /// only.
351 const char *getEdgeKindName(Edge::Kind K);
352 
353 /// Returns true if the given uint64_t value is in range for a uint32_t.
356 }
357 
358 /// Returns true if the given int64_t value is in range for an int32_t.
359 inline bool isInRangeForImmS32(int64_t Value) {
362 }
363 
364 /// Apply fixup expression for edge to block content.
365 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
366  const Symbol *GOTSymbol) {
367  using namespace support;
368 
369  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
370  char *FixupPtr = BlockWorkingMem + E.getOffset();
371  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
372 
373  switch (E.getKind()) {
374 
375  case Pointer64: {
376  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
377  *(ulittle64_t *)FixupPtr = Value;
378  break;
379  }
380 
381  case Pointer32: {
382  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
384  *(ulittle32_t *)FixupPtr = Value;
385  else
386  return makeTargetOutOfRangeError(G, B, E);
387  break;
388  }
389  case Pointer32Signed: {
390  int64_t Value = E.getTarget().getAddress() + E.getAddend();
392  *(little32_t *)FixupPtr = Value;
393  else
394  return makeTargetOutOfRangeError(G, B, E);
395  break;
396  }
397 
398  case BranchPCRel32:
404  int64_t Value =
405  E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
407  *(little32_t *)FixupPtr = Value;
408  else
409  return makeTargetOutOfRangeError(G, B, E);
410  break;
411  }
412 
413  case Delta64: {
414  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
415  *(little64_t *)FixupPtr = Value;
416  break;
417  }
418 
419  case Delta32: {
420  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
422  *(little32_t *)FixupPtr = Value;
423  else
424  return makeTargetOutOfRangeError(G, B, E);
425  break;
426  }
427 
428  case NegDelta64: {
429  int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
430  *(little64_t *)FixupPtr = Value;
431  break;
432  }
433 
434  case NegDelta32: {
435  int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
437  *(little32_t *)FixupPtr = Value;
438  else
439  return makeTargetOutOfRangeError(G, B, E);
440  break;
441  }
442  case Delta64FromGOT: {
443  assert(GOTSymbol && "No GOT section symbol");
444  int64_t Value =
445  E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
446  *(little64_t *)FixupPtr = Value;
447  break;
448  }
449 
450  default: {
451  // If you hit this you should check that *constructor and other non-fixup
452  // edges have been removed prior to applying fixups.
453  llvm_unreachable("Graph contains edge kind with no fixup expression");
454  }
455  }
456 
457  return Error::success();
458 }
459 
460 /// x86_64 pointer size.
461 constexpr uint64_t PointerSize = 8;
462 
463 /// x86-64 null pointer content.
464 extern const char NullPointerContent[PointerSize];
465 
466 /// x86-64 pointer jump stub content.
467 ///
468 /// Contains the instruction sequence for an indirect jump via an in-memory
469 /// pointer:
470 /// jmpq *ptr(%rip)
471 extern const char PointerJumpStubContent[6];
472 
473 /// Creates a new pointer block in the given section and returns an anonymous
474 /// symbol pointing to it.
475 ///
476 /// If InitialTarget is given then an Pointer64 relocation will be added to the
477 /// block pointing at InitialTarget.
478 ///
479 /// The pointer block will have the following default values:
480 /// alignment: 64-bit
481 /// alignment-offset: 0
482 /// address: highest allowable (~7U)
483 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
484  Symbol *InitialTarget = nullptr,
485  uint64_t InitialAddend = 0) {
486  auto &B =
487  G.createContentBlock(PointerSection, NullPointerContent, ~7ULL, 8, 0);
488  if (InitialTarget)
489  B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
490  return G.addAnonymousSymbol(B, 0, 8, false, false);
491 }
492 
493 /// Create a jump stub block that jumps via the pointer at the given symbol.
494 ///
495 /// The stub block will have the following default values:
496 /// alignment: 8-bit
497 /// alignment-offset: 0
498 /// address: highest allowable: (~5U)
500  Symbol &PointerSymbol) {
501  auto &B =
502  G.createContentBlock(StubSection, PointerJumpStubContent, ~5ULL, 1, 0);
503  B.addEdge(Delta32, 2, PointerSymbol, -4);
504  return B;
505 }
506 
507 /// Create a jump stub that jumps via the pointer at the given symbol and
508 /// an anonymous symbol pointing to it. Return the anonymous symbol.
509 ///
510 /// The stub block will be created by createPointerJumpStubBlock.
512  Section &StubSection,
513  Symbol &PointerSymbol) {
514  return G.addAnonymousSymbol(
515  createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
516  false);
517 }
518 
519 /// Global Offset Table Builder.
520 class GOTTableManager : public TableManager<GOTTableManager> {
521 public:
522  static StringRef getSectionName() { return "$__GOT"; }
523 
525  Edge::Kind KindToSet = Edge::Invalid;
526  switch (E.getKind()) {
527  case x86_64::Delta64FromGOT: {
528  // we need to make sure that the GOT section exists, but don't otherwise
529  // need to fix up this edge
530  getGOTSection(G);
531  return false;
532  }
535  break;
538  break;
540  KindToSet = x86_64::Delta64;
541  break;
543  KindToSet = x86_64::Delta64FromGOT;
544  break;
546  KindToSet = x86_64::Delta32;
547  break;
548  default:
549  return false;
550  }
551  assert(KindToSet != Edge::Invalid &&
552  "Fell through switch, but no new kind to set");
553  DEBUG_WITH_TYPE("jitlink", {
554  dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
555  << formatv("{0:x}", B->getFixupAddress(E)) << " ("
556  << formatv("{0:x}", B->getAddress()) << " + "
557  << formatv("{0:x}", E.getOffset()) << ")\n";
558  });
559  E.setKind(KindToSet);
560  E.setTarget(getEntryForTarget(G, E.getTarget()));
561  return true;
562  }
563 
565  return createAnonymousPointer(G, getGOTSection(G), &Target);
566  }
567 
568 private:
569  Section &getGOTSection(LinkGraph &G) {
570  if (!GOTSection)
571  GOTSection = &G.createSection(getSectionName(), MemProt::Read);
572  return *GOTSection;
573  }
574 
575  Section *GOTSection = nullptr;
576 };
577 
578 /// Procedure Linkage Table Builder.
579 class PLTTableManager : public TableManager<PLTTableManager> {
580 public:
582 
583  static StringRef getSectionName() { return "$__STUBS"; }
584 
586  if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
587  DEBUG_WITH_TYPE("jitlink", {
588  dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
589  << formatv("{0:x}", B->getFixupAddress(E)) << " ("
590  << formatv("{0:x}", B->getAddress()) << " + "
591  << formatv("{0:x}", E.getOffset()) << ")\n";
592  });
593  // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
594  // be optimized when the target is in-range.
596  E.setTarget(getEntryForTarget(G, E.getTarget()));
597  return true;
598  }
599  return false;
600  }
601 
605  }
606 
607 public:
609  if (!PLTSection)
610  PLTSection =
611  &G.createSection(getSectionName(), MemProt::Read | MemProt::Exec);
612  return *PLTSection;
613  }
614 
616  Section *PLTSection = nullptr;
617 };
618 
619 /// Optimize the GOT and Stub relocations if the edge target address is in range
620 /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
621 /// then replace GOT load with lea
622 /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
623 /// in range, replace a indirect jump by plt stub with a direct jump to the
624 /// target
626 
627 } // namespace x86_64
628 } // end namespace jitlink
629 } // end namespace llvm
630 
631 #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:137
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:250
llvm::support::little64_t
detail::packed_endian_specific_integral< int64_t, little, unaligned > little64_t
Definition: Endian.h:281
DEBUG_WITH_TYPE
#define DEBUG_WITH_TYPE(TYPE, X)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition: Debug.h:64
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::support::ulittle32_t
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:272
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
uint64_t
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::support::little32_t
detail::packed_endian_specific_integral< int32_t, little, unaligned > little32_t
Definition: Endian.h:279
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
TableManager.h
llvm::support::ulittle64_t
detail::packed_endian_specific_integral< uint64_t, little, unaligned > ulittle64_t
Definition: Endian.h:274
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:340
support
Reimplement select in terms of SEL *We would really like to support but we need to prove that the add doesn t need to overflow between the two bit chunks *Implement pre post increment support(e.g. PR935) *Implement smarter const ant generation for binops with large immediates. A few ARMv6T2 ops should be pattern matched
Definition: README.txt:10
LLVM_LIKELY
#define LLVM_LIKELY(EXPR)
Definition: Compiler.h:225
llvm::Value
LLVM Value Representation.
Definition: Value.h:74