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 
17 
18 #include <limits>
19 
20 namespace llvm {
21 namespace jitlink {
22 namespace x86_64 {
23 
24 /// Represents x86-64 fixups and other x86-64-specific edge kinds.
26 
27  /// A plain 64-bit pointer value relocation.
28  ///
29  /// Fixup expression:
30  /// Fixup <- Target + Addend : uint64
31  ///
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  ///
44 
45  /// A 64-bit delta.
46  ///
47  /// Delta from the fixup to the target.
48  ///
49  /// Fixup expression:
50  /// Fixup <- Target - Fixup + Addend : int64
51  ///
53 
54  /// A 32-bit delta.
55  ///
56  /// Delta from the fixup to the target.
57  ///
58  /// Fixup expression:
59  /// Fixup <- Target - Fixup + Addend : int64
60  ///
61  /// Errors:
62  /// - The result of the fixup expression must fit into an int32, otherwise
63  /// an out-of-range error will be returned.
64  ///
66 
67  /// A 64-bit negative delta.
68  ///
69  /// Delta from target back to the fixup.
70  ///
71  /// Fixup expression:
72  /// Fixup <- Fixup - Target + Addend : int64
73  ///
75 
76  /// A 32-bit negative delta.
77  ///
78  /// Delta from the target back to the fixup.
79  ///
80  /// Fixup expression:
81  /// Fixup <- Fixup - Target + Addend : int32
82  ///
83  /// Errors:
84  /// - The result of the fixup expression must fit into an int32, otherwise
85  /// an out-of-range error will be returned.
87 
88  /// A 32-bit PC-relative branch.
89  ///
90  /// Represents a PC-relative call or branch to a target. This can be used to
91  /// identify, record, and/or patch call sites.
92  ///
93  /// The fixup expression for this kind includes an implicit offset to account
94  /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
95  /// T and addend zero is a call/branch to the start (offset zero) of T.
96  ///
97  /// Fixup expression:
98  /// Fixup <- Target - (Fixup + 4) + Addend : int32
99  ///
100  /// Errors:
101  /// - The result of the fixup expression must fit into an int32, otherwise
102  /// an out-of-range error will be returned.
103  ///
105 
106  /// A 32-bit PC-relative branch to a pointer jump stub.
107  ///
108  /// The target of this relocation should be a pointer jump stub of the form:
109  ///
110  /// \code{.s}
111  /// .text
112  /// jmpq *tgtptr(%rip)
113  /// ; ...
114  ///
115  /// .data
116  /// tgtptr:
117  /// .quad 0
118  /// \endcode
119  ///
120  /// This edge kind has the same fixup expression as BranchPCRel32, but further
121  /// identifies the call/branch as being to a pointer jump stub. For edges of
122  /// this kind the jump stub should not be bypassed (use
123  /// BranchPCRel32ToPtrJumpStubRelaxable for that), but the pointer location
124  /// target may be recorded to allow manipulation at runtime.
125  ///
126  /// Fixup expression:
127  /// Fixup <- Target - Fixup + Addend - 4 : int32
128  ///
129  /// Errors:
130  /// - The result of the fixup expression must fit into an int32, otherwise
131  /// an out-of-range error will be returned.
132  ///
134 
135  /// A relaxable version of BranchPCRel32ToPtrJumpStub.
136  ///
137  /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
138  /// but identifies the call/branch as being to a pointer jump stub that may be
139  /// bypassed if the ultimate target is within range of the fixup location.
140  ///
141  /// Fixup expression:
142  /// Fixup <- Target - Fixup + Addend - 4: int32
143  ///
144  /// Errors:
145  /// - The result of the fixup expression must fit into an int32, otherwise
146  /// an out-of-range error will be returned.
147  ///
149 
150  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
151  /// entry for the original target.
152  ///
153  /// Indicates that this edge should be transformed into a Delta32 targeting
154  /// the GOT entry for the edge's current target, maintaining the same addend.
155  /// A GOT entry for the target should be created if one does not already
156  /// exist.
157  ///
158  /// Edges of this kind are usually handled by a GOT builder pass inserted by
159  /// default.
160  ///
161  /// Fixup expression:
162  /// NONE
163  ///
164  /// Errors:
165  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
166  /// phase will result in an assert/unreachable during the fixup phase.
167  ///
169 
170  /// A PC-relative reference to a GOT entry, relaxable if GOT entry target
171  /// is in-range of the fixup.
172  ///
173  /// If the GOT entry target is in-range of the fixup then the load from the
174  /// GOT may be replaced with a direct memory address calculation.
175  ///
176  /// Fixup expression:
177  /// Fixup <- Target - (Fixup + 4) + Addend : int32
178  ///
179  /// Errors:
180  /// - The result of the fixup expression must fit into an int32, otherwise
181  /// an out-of-range error will be returned.
182  ///
184 
185  /// A GOT entry getter/constructor, transformed to PCRel32ToGOTLoadRelaxable
186  /// pointing at the GOT entry for the original target.
187  ///
188  /// Indicates that this edge should be transformed into a
189  /// PC32ToGOTLoadRelaxable targeting the GOT entry for the edge's current
190  /// target, maintaining the same addend. A GOT entry for the target should be
191  /// created if one does not already exist.
192  ///
193  /// Edges of this kind are usually handled by a GOT builder pass inserted by
194  /// default.
195  ///
196  /// Fixup expression:
197  /// NONE
198  ///
199  /// Errors:
200  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
201  /// phase will result in an assert/unreachable during the fixup phase.
202  ///
204 
205  /// A PC-relative reference to a Thread Local Variable Pointer (TLVP) entry,
206  /// relaxable if the TLVP entry target is in-range of the fixup.
207  ///
208  /// If the TLVP entry target is in-range of the fixup then the load frmo the
209  /// TLVP may be replaced with a direct memory address calculation.
210  ///
211  /// The target of this edge must be a thread local variable entry of the form
212  /// .quad <tlv getter thunk>
213  /// .quad <tlv key>
214  /// .quad <tlv initializer>
215  ///
216  /// Fixup expression:
217  /// Fixup <- Target - (Fixup + 4) + Addend : 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  /// - The target must be either external, or a TLV entry of the required
223  /// form, otherwise a malformed TLV entry error will be returned.
224  ///
226 
227  /// A TLVP entry getter/constructor, transformed to
228  /// Delta32ToTLVPLoadRelaxable.
229  ///
230  /// Indicates that this edge should be transformed into a
231  /// Delta32ToTLVPLoadRelaxable targeting the TLVP entry for the edge's current
232  /// target. A TLVP entry for the target should be created if one does not
233  /// already exist.
234  ///
235  /// Fixup expression:
236  /// NONE
237  ///
238  /// Errors:
239  /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
240  /// phase will result in an assert/unreachable during the fixup phase.
241  ///
243 };
244 
245 /// Returns a string name for the given x86-64 edge. For debugging purposes
246 /// only.
247 const char *getEdgeKindName(Edge::Kind K);
248 
249 /// Returns true if the given uint64_t value is in range for a uint32_t.
250 inline bool isInRangeForImmU32(uint64_t Value) {
252 }
253 
254 /// Returns true if the given int64_t value is in range for an int32_t.
255 inline bool isInRangeForImmS32(int64_t Value) {
258 }
259 
260 /// Apply fixup expression for edge to block content.
261 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
262  using namespace support;
263 
264  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
265  char *FixupPtr = BlockWorkingMem + E.getOffset();
266  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
267 
268  switch (E.getKind()) {
269 
270  case Pointer64: {
271  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
272  *(ulittle64_t *)FixupPtr = Value;
273  break;
274  }
275 
276  case Pointer32: {
277  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
279  *(ulittle32_t *)FixupPtr = Value;
280  else
281  return makeTargetOutOfRangeError(G, B, E);
282  break;
283  }
284 
285  case BranchPCRel32:
290  int64_t Value =
291  E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
293  *(little32_t *)FixupPtr = Value;
294  else
295  return makeTargetOutOfRangeError(G, B, E);
296  break;
297  }
298 
299  case Delta64: {
300  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
301  *(little64_t *)FixupPtr = Value;
302  break;
303  }
304 
305  case Delta32: {
306  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
308  *(little32_t *)FixupPtr = Value;
309  else
310  return makeTargetOutOfRangeError(G, B, E);
311  break;
312  }
313 
314  case NegDelta64: {
315  int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
316  *(little64_t *)FixupPtr = Value;
317  break;
318  }
319 
320  case NegDelta32: {
321  int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
323  *(little32_t *)FixupPtr = Value;
324  else
325  return makeTargetOutOfRangeError(G, B, E);
326  break;
327  }
328 
329  default: {
330  // If you hit this you should check that *constructor and other non-fixup
331  // edges have been removed prior to applying fixups.
332  llvm_unreachable("Graph contains edge kind with no fixup expression");
333  }
334  }
335 
336  return Error::success();
337 }
338 
339 /// x86_64 pointer size.
340 constexpr uint64_t PointerSize = 8;
341 
342 /// x86-64 null pointer content.
343 extern const char NullPointerContent[PointerSize];
344 
345 /// x86-64 pointer jump stub content.
346 ///
347 /// Contains the instruction sequence for an indirect jump via an in-memory
348 /// pointer:
349 /// jmpq *ptr(%rip)
350 extern const char PointerJumpStubContent[6];
351 
352 /// Creates a new pointer block in the given section and returns an anonymous
353 /// symbol pointing to it.
354 ///
355 /// If InitialTarget is given then an Pointer64 relocation will be added to the
356 /// block pointing at InitialTarget.
357 ///
358 /// The pointer block will have the following default values:
359 /// alignment: 64-bit
360 /// alignment-offset: 0
361 /// address: highest allowable (~7U)
362 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
363  Symbol *InitialTarget = nullptr,
364  uint64_t InitialAddend = 0) {
365  auto &B =
366  G.createContentBlock(PointerSection, NullPointerContent, ~7ULL, 8, 0);
367  if (InitialTarget)
368  B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
369  return G.addAnonymousSymbol(B, 0, 8, false, false);
370 }
371 
372 /// Create a jump stub block that jumps via the pointer at the given symbol.
373 ///
374 /// The stub block will have the following default values:
375 /// alignment: 8-bit
376 /// alignment-offset: 0
377 /// address: highest allowable: (~5U)
379  Symbol &PointerSymbol) {
380  auto &B =
381  G.createContentBlock(StubSection, PointerJumpStubContent, ~5ULL, 1, 0);
382  B.addEdge(Delta32, 2, PointerSymbol, -4);
383  return B;
384 }
385 
386 /// Create a jump stub that jumps via the pointer at the given symbol and
387 /// an anonymous symbol pointing to it. Return the anonymous symbol.
388 ///
389 /// The stub block will be created by createPointerJumpStubBlock.
391  Section &StubSection,
392  Symbol &PointerSymbol) {
393  return G.addAnonymousSymbol(
394  createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
395  false);
396 }
397 
398 } // namespace x86_64
399 } // end namespace jitlink
400 } // end namespace llvm
401 
402 #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::support::little64_t
detail::packed_endian_specific_integral< int64_t, little, unaligned > little64_t
Definition: Endian.h:281
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
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:136
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
llvm::JITTargetAddress
uint64_t JITTargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:42
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:219
llvm::Value
LLVM Value Representation.
Definition: Value.h:75