LLVM  12.0.0git
MachO_x86_64.cpp
Go to the documentation of this file.
1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
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 // MachO/x86-64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
16 #include "MachOLinkGraphBuilder.h"
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 using namespace llvm::jitlink::MachO_x86_64_Edges;
23 
24 namespace {
25 
26 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
27 public:
28  MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
29  : MachOLinkGraphBuilder(Obj) {}
30 
31 private:
33  getRelocationKind(const MachO::relocation_info &RI) {
34  switch (RI.r_type) {
36  if (!RI.r_pcrel) {
37  if (RI.r_length == 3)
38  return RI.r_extern ? Pointer64 : Pointer64Anon;
39  else if (RI.r_extern && RI.r_length == 2)
40  return Pointer32;
41  }
42  break;
44  if (RI.r_pcrel && RI.r_length == 2)
45  return RI.r_extern ? PCRel32 : PCRel32Anon;
46  break;
48  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
49  return Branch32;
50  break;
52  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
53  return PCRel32GOTLoad;
54  break;
56  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
57  return PCRel32GOT;
58  break;
60  // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
61  // Initially represent SUBTRACTOR relocations with 'Delta<W>'. They may
62  // be turned into NegDelta<W> by parsePairRelocation.
63  if (!RI.r_pcrel && RI.r_extern) {
64  if (RI.r_length == 2)
65  return Delta32;
66  else if (RI.r_length == 3)
67  return Delta64;
68  }
69  break;
71  if (RI.r_pcrel && RI.r_length == 2)
73  break;
75  if (RI.r_pcrel && RI.r_length == 2)
77  break;
79  if (RI.r_pcrel && RI.r_length == 2)
81  break;
83  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
84  return PCRel32TLV;
85  break;
86  }
87 
88  return make_error<JITLinkError>(
89  "Unsupported x86-64 relocation: address=" +
90  formatv("{0:x8}", RI.r_address) +
91  ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
92  ", kind=" + formatv("{0:x1}", RI.r_type) +
93  ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
94  ", extern=" + (RI.r_extern ? "true" : "false") +
95  ", length=" + formatv("{0:d}", RI.r_length));
96  }
97 
98  using PairRelocInfo = std::tuple<MachOX86RelocationKind, Symbol *, uint64_t>;
99 
100  // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
101  // returns the edge kind and addend to be used.
103  parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
104  const MachO::relocation_info &SubRI,
105  JITTargetAddress FixupAddress, const char *FixupContent,
106  object::relocation_iterator &UnsignedRelItr,
107  object::relocation_iterator &RelEnd) {
108  using namespace support;
109 
110  assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
111  (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
112  "Subtractor kind should match length");
113  assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
114  assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
115 
116  if (UnsignedRelItr == RelEnd)
117  return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
118  "UNSIGNED relocation");
119 
120  auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
121 
122  if (SubRI.r_address != UnsignedRI.r_address)
123  return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
124  "point to different addresses");
125 
126  if (SubRI.r_length != UnsignedRI.r_length)
127  return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
128  "UNSIGNED reloc must match");
129 
130  Symbol *FromSymbol;
131  if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
132  FromSymbol = FromSymbolOrErr->GraphSymbol;
133  else
134  return FromSymbolOrErr.takeError();
135 
136  // Read the current fixup value.
137  uint64_t FixupValue = 0;
138  if (SubRI.r_length == 3)
139  FixupValue = *(const little64_t *)FixupContent;
140  else
141  FixupValue = *(const little32_t *)FixupContent;
142 
143  // Find 'ToSymbol' using symbol number or address, depending on whether the
144  // paired UNSIGNED relocation is extern.
145  Symbol *ToSymbol = nullptr;
146  if (UnsignedRI.r_extern) {
147  // Find target symbol by symbol index.
148  if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
149  ToSymbol = ToSymbolOrErr->GraphSymbol;
150  else
151  return ToSymbolOrErr.takeError();
152  } else {
153  if (auto ToSymbolOrErr = findSymbolByAddress(FixupValue))
154  ToSymbol = &*ToSymbolOrErr;
155  else
156  return ToSymbolOrErr.takeError();
157  FixupValue -= ToSymbol->getAddress();
158  }
159 
160  MachOX86RelocationKind DeltaKind;
161  Symbol *TargetSymbol;
162  uint64_t Addend;
163  if (&BlockToFix == &FromSymbol->getAddressable()) {
164  TargetSymbol = ToSymbol;
165  DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
166  Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
167  // FIXME: handle extern 'from'.
168  } else if (&BlockToFix == &ToSymbol->getAddressable()) {
169  TargetSymbol = FromSymbol;
170  DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
171  Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
172  } else {
173  // BlockToFix was neither FromSymbol nor ToSymbol.
174  return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
175  "either 'A' or 'B' (or a symbol in one "
176  "of their alt-entry chains)");
177  }
178 
179  return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
180  }
181 
182  Error addRelocations() override {
183  using namespace support;
184  auto &Obj = getObject();
185 
186  for (auto &S : Obj.sections()) {
187 
188  JITTargetAddress SectionAddress = S.getAddress();
189 
190  // Skip relocations virtual sections.
191  if (S.isVirtual()) {
192  if (S.relocation_begin() != S.relocation_end())
193  return make_error<JITLinkError>("Virtual section contains "
194  "relocations");
195  continue;
196  }
197 
198  // Skip relocations for debug symbols.
199  {
200  auto &NSec =
201  getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
202  if (!NSec.GraphSection) {
203  LLVM_DEBUG({
204  dbgs() << "Skipping relocations for MachO section " << NSec.SegName
205  << "/" << NSec.SectName
206  << " which has no associated graph section\n";
207  });
208  continue;
209  }
210  }
211 
212  // Add relocations for section.
213  for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
214  RelItr != RelEnd; ++RelItr) {
215 
216  MachO::relocation_info RI = getRelocationInfo(RelItr);
217 
218  // Sanity check the relocation kind.
219  auto Kind = getRelocationKind(RI);
220  if (!Kind)
221  return Kind.takeError();
222 
223  // Find the address of the value to fix up.
224  JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
225 
226  LLVM_DEBUG({
227  dbgs() << "Processing relocation at "
228  << format("0x%016" PRIx64, FixupAddress) << "\n";
229  });
230 
231  // Find the block that the fixup points to.
232  Block *BlockToFix = nullptr;
233  {
234  auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
235  if (!SymbolToFixOrErr)
236  return SymbolToFixOrErr.takeError();
237  BlockToFix = &SymbolToFixOrErr->getBlock();
238  }
239 
240  if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
241  BlockToFix->getAddress() + BlockToFix->getContent().size())
242  return make_error<JITLinkError>(
243  "Relocation extends past end of fixup block");
244 
245  // Get a pointer to the fixup content.
246  const char *FixupContent = BlockToFix->getContent().data() +
247  (FixupAddress - BlockToFix->getAddress());
248 
249  // The target symbol and addend will be populated by the switch below.
250  Symbol *TargetSymbol = nullptr;
251  uint64_t Addend = 0;
252 
253  switch (*Kind) {
254  case Branch32:
255  case PCRel32:
256  case PCRel32GOTLoad:
257  case PCRel32GOT:
258  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
259  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
260  else
261  return TargetSymbolOrErr.takeError();
262  Addend = *(const little32_t *)FixupContent;
263  break;
264  case Pointer32:
265  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
266  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
267  else
268  return TargetSymbolOrErr.takeError();
269  Addend = *(const ulittle32_t *)FixupContent;
270  break;
271  case Pointer64:
272  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
273  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
274  else
275  return TargetSymbolOrErr.takeError();
276  Addend = *(const ulittle64_t *)FixupContent;
277  break;
278  case Pointer64Anon: {
279  JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
280  if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
281  TargetSymbol = &*TargetSymbolOrErr;
282  else
283  return TargetSymbolOrErr.takeError();
284  Addend = TargetAddress - TargetSymbol->getAddress();
285  break;
286  }
287  case PCRel32Minus1:
288  case PCRel32Minus2:
289  case PCRel32Minus4:
290  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
291  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
292  else
293  return TargetSymbolOrErr.takeError();
294  Addend = *(const little32_t *)FixupContent +
295  (1 << (*Kind - PCRel32Minus1));
296  break;
297  case PCRel32Anon: {
298  JITTargetAddress TargetAddress =
299  FixupAddress + 4 + *(const little32_t *)FixupContent;
300  if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
301  TargetSymbol = &*TargetSymbolOrErr;
302  else
303  return TargetSymbolOrErr.takeError();
304  Addend = TargetAddress - TargetSymbol->getAddress();
305  break;
306  }
307  case PCRel32Minus1Anon:
308  case PCRel32Minus2Anon:
309  case PCRel32Minus4Anon: {
310  JITTargetAddress Delta =
311  static_cast<JITTargetAddress>(1ULL << (*Kind - PCRel32Minus1Anon));
312  JITTargetAddress TargetAddress =
313  FixupAddress + 4 + Delta + *(const little32_t *)FixupContent;
314  if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
315  TargetSymbol = &*TargetSymbolOrErr;
316  else
317  return TargetSymbolOrErr.takeError();
318  Addend = TargetAddress - TargetSymbol->getAddress();
319  break;
320  }
321  case Delta32:
322  case Delta64: {
323  // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
324  // parsePairRelocation handles the paired reloc, and returns the
325  // edge kind to be used (either Delta32/Delta64, or
326  // NegDelta32/NegDelta64, depending on the direction of the
327  // subtraction) along with the addend.
328  auto PairInfo =
329  parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
330  FixupContent, ++RelItr, RelEnd);
331  if (!PairInfo)
332  return PairInfo.takeError();
333  std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
334  assert(TargetSymbol && "No target symbol from parsePairRelocation?");
335  break;
336  }
337  default:
338  llvm_unreachable("Special relocation kind should not appear in "
339  "mach-o file");
340  }
341 
342  LLVM_DEBUG({
343  Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
344  Addend);
345  printEdge(dbgs(), *BlockToFix, GE,
347  dbgs() << "\n";
348  });
349  BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
350  *TargetSymbol, Addend);
351  }
352  }
353  return Error::success();
354  }
355 };
356 
357 class MachO_x86_64_GOTAndStubsBuilder
358  : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
359 public:
360  static const uint8_t NullGOTEntryContent[8];
361  static const uint8_t StubContent[6];
362 
363  MachO_x86_64_GOTAndStubsBuilder(LinkGraph &G)
365 
366  bool isGOTEdge(Edge &E) const {
367  return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
368  }
369 
370  Symbol &createGOTEntry(Symbol &Target) {
371  auto &GOTEntryBlock = G.createContentBlock(
372  getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
373  GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
374  return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
375  }
376 
377  void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
378  assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
379  "Not a GOT edge?");
380  // If this is a PCRel32GOT then change it to an ordinary PCRel32. If it is
381  // a PCRel32GOTLoad then leave it as-is for now. We will use the kind to
382  // check for GOT optimization opportunities in the
383  // optimizeMachO_x86_64_GOTAndStubs pass below.
384  if (E.getKind() == PCRel32GOT)
385  E.setKind(PCRel32);
386 
387  E.setTarget(GOTEntry);
388  // Leave the edge addend as-is.
389  }
390 
391  bool isExternalBranchEdge(Edge &E) {
392  return E.getKind() == Branch32 && !E.getTarget().isDefined();
393  }
394 
395  Symbol &createStub(Symbol &Target) {
396  auto &StubContentBlock =
397  G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
398  // Re-use GOT entries for stub targets.
399  auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
400  StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, 0);
401  return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
402  }
403 
404  void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
405  assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
406  assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
407 
408  // Set the edge kind to Branch32ToStub. We will use this to check for stub
409  // optimization opportunities in the optimizeMachO_x86_64_GOTAndStubs pass
410  // below.
412  E.setTarget(Stub);
413  }
414 
415 private:
416  Section &getGOTSection() {
417  if (!GOTSection)
418  GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
419  return *GOTSection;
420  }
421 
422  Section &getStubsSection() {
423  if (!StubsSection) {
424  auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
426  StubsSection = &G.createSection("$__STUBS", StubsProt);
427  }
428  return *StubsSection;
429  }
430 
431  StringRef getGOTEntryBlockContent() {
432  return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
433  sizeof(NullGOTEntryContent));
434  }
435 
436  StringRef getStubBlockContent() {
437  return StringRef(reinterpret_cast<const char *>(StubContent),
438  sizeof(StubContent));
439  }
440 
441  Section *GOTSection = nullptr;
442  Section *StubsSection = nullptr;
443 };
444 
445 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
446  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
447 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
448  0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
449 } // namespace
450 
452  LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
453 
454  for (auto *B : G.blocks())
455  for (auto &E : B->edges())
456  if (E.getKind() == PCRel32GOTLoad) {
457  assert(E.getOffset() >= 3 && "GOT edge occurs too early in block");
458 
459  // Switch the edge kind to PCRel32: Whether we change the edge target
460  // or not this will be the desired kind.
461  E.setKind(PCRel32);
462 
463  // Optimize GOT references.
464  auto &GOTBlock = E.getTarget().getBlock();
465  assert(GOTBlock.getSize() == G.getPointerSize() &&
466  "GOT entry block should be pointer sized");
467  assert(GOTBlock.edges_size() == 1 &&
468  "GOT entry should only have one outgoing edge");
469 
470  auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
471  JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
472  JITTargetAddress TargetAddr = GOTTarget.getAddress();
473 
474  // Check that this is a recognized MOV instruction.
475  // FIXME: Can we assume this?
476  constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b};
477  if (strncmp(B->getContent().data() + E.getOffset() - 3,
478  reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0)
479  continue;
480 
481  int64_t Displacement = TargetAddr - EdgeAddr + 4;
482  if (Displacement >= std::numeric_limits<int32_t>::min() &&
484  E.setTarget(GOTTarget);
485  auto *BlockData = reinterpret_cast<uint8_t *>(
486  const_cast<char *>(B->getContent().data()));
487  BlockData[E.getOffset() - 2] = 0x8d;
488  LLVM_DEBUG({
489  dbgs() << " Replaced GOT load wih LEA:\n ";
490  printEdge(dbgs(), *B, E,
491  getMachOX86RelocationKindName(E.getKind()));
492  dbgs() << "\n";
493  });
494  }
495  } else if (E.getKind() == Branch32ToStub) {
496 
497  // Switch the edge kind to PCRel32: Whether we change the edge target
498  // or not this will be the desired kind.
499  E.setKind(Branch32);
500 
501  auto &StubBlock = E.getTarget().getBlock();
502  assert(StubBlock.getSize() ==
503  sizeof(MachO_x86_64_GOTAndStubsBuilder::StubContent) &&
504  "Stub block should be stub sized");
505  assert(StubBlock.edges_size() == 1 &&
506  "Stub block should only have one outgoing edge");
507 
508  auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
509  assert(GOTBlock.getSize() == G.getPointerSize() &&
510  "GOT block should be pointer sized");
511  assert(GOTBlock.edges_size() == 1 &&
512  "GOT block should only have one outgoing edge");
513 
514  auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
515  JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
516  JITTargetAddress TargetAddr = GOTTarget.getAddress();
517 
518  int64_t Displacement = TargetAddr - EdgeAddr + 4;
519  if (Displacement >= std::numeric_limits<int32_t>::min() &&
520  Displacement <= std::numeric_limits<int32_t>::max()) {
521  E.setTarget(GOTTarget);
522  LLVM_DEBUG({
523  dbgs() << " Replaced stub branch with direct branch:\n ";
524  printEdge(dbgs(), *B, E,
525  getMachOX86RelocationKindName(E.getKind()));
526  dbgs() << "\n";
527  });
528  }
529  }
530 
531  return Error::success();
532 }
533 
534 namespace llvm {
535 namespace jitlink {
536 
537 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
539 
540 public:
541  MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
542  PassConfiguration PassConfig)
543  : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
544 
545 private:
546  StringRef getEdgeKindName(Edge::Kind R) const override {
548  }
549 
551  buildGraph(MemoryBufferRef ObjBuffer) override {
552  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
553  if (!MachOObj)
554  return MachOObj.takeError();
555  return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
556  }
557 
558  static Error targetOutOfRangeError(const Block &B, const Edge &E) {
559  std::string ErrMsg;
560  {
561  raw_string_ostream ErrStream(ErrMsg);
562  ErrStream << "Relocation target out of range: ";
563  printEdge(ErrStream, B, E, getMachOX86RelocationKindName(E.getKind()));
564  ErrStream << "\n";
565  }
566  return make_error<JITLinkError>(std::move(ErrMsg));
567  }
568 
569  Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
570 
571  using namespace support;
572 
573  char *FixupPtr = BlockWorkingMem + E.getOffset();
574  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
575 
576  switch (E.getKind()) {
577  case Branch32:
578  case PCRel32:
579  case PCRel32Anon: {
580  int64_t Value =
581  E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
582  if (Value < std::numeric_limits<int32_t>::min() ||
584  return targetOutOfRangeError(B, E);
585  *(little32_t *)FixupPtr = Value;
586  break;
587  }
588  case Pointer64:
589  case Pointer64Anon: {
590  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
591  *(ulittle64_t *)FixupPtr = Value;
592  break;
593  }
594  case PCRel32Minus1:
595  case PCRel32Minus2:
596  case PCRel32Minus4: {
597  int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
598  int64_t Value =
599  E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
600  if (Value < std::numeric_limits<int32_t>::min() ||
602  return targetOutOfRangeError(B, E);
603  *(little32_t *)FixupPtr = Value;
604  break;
605  }
606  case PCRel32Minus1Anon:
607  case PCRel32Minus2Anon:
608  case PCRel32Minus4Anon: {
609  int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
610  int64_t Value =
611  E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
612  if (Value < std::numeric_limits<int32_t>::min() ||
614  return targetOutOfRangeError(B, E);
615  *(little32_t *)FixupPtr = Value;
616  break;
617  }
618  case Delta32:
619  case Delta64:
620  case NegDelta32:
621  case NegDelta64: {
622  int64_t Value;
623  if (E.getKind() == Delta32 || E.getKind() == Delta64)
624  Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
625  else
626  Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
627 
628  if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
629  if (Value < std::numeric_limits<int32_t>::min() ||
631  return targetOutOfRangeError(B, E);
632  *(little32_t *)FixupPtr = Value;
633  } else
634  *(little64_t *)FixupPtr = Value;
635  break;
636  }
637  case Pointer32: {
638  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
640  return targetOutOfRangeError(B, E);
641  *(ulittle32_t *)FixupPtr = Value;
642  break;
643  }
644  default:
645  llvm_unreachable("Unrecognized edge kind");
646  }
647 
648  return Error::success();
649  }
650 
651  uint64_t NullValue = 0;
652 };
653 
654 void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
655  PassConfiguration Config;
656  Triple TT("x86_64-apple-macosx");
657 
658  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
659  // Add eh-frame passses.
660  Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame"));
661  Config.PrePrunePasses.push_back(
662  EHFrameEdgeFixer("__eh_frame", NegDelta32, Delta64, Delta64));
663 
664  // Add a mark-live pass.
665  if (auto MarkLive = Ctx->getMarkLivePass(TT))
666  Config.PrePrunePasses.push_back(std::move(MarkLive));
667  else
668  Config.PrePrunePasses.push_back(markAllSymbolsLive);
669 
670  // Add an in-place GOT/Stubs pass.
671  Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
672  MachO_x86_64_GOTAndStubsBuilder(G).run();
673  return Error::success();
674  });
675 
676  // Add GOT/Stubs optimizer pass.
678  }
679 
680  if (auto Err = Ctx->modifyPassConfig(TT, Config))
681  return Ctx->notifyFailed(std::move(Err));
682 
683  // Construct a JITLinker and run the link function.
684  MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
685 }
686 
688  switch (R) {
689  case Branch32:
690  return "Branch32";
691  case Branch32ToStub:
692  return "Branch32ToStub";
693  case Pointer32:
694  return "Pointer32";
695  case Pointer64:
696  return "Pointer64";
697  case Pointer64Anon:
698  return "Pointer64Anon";
699  case PCRel32:
700  return "PCRel32";
701  case PCRel32Minus1:
702  return "PCRel32Minus1";
703  case PCRel32Minus2:
704  return "PCRel32Minus2";
705  case PCRel32Minus4:
706  return "PCRel32Minus4";
707  case PCRel32Anon:
708  return "PCRel32Anon";
709  case PCRel32Minus1Anon:
710  return "PCRel32Minus1Anon";
711  case PCRel32Minus2Anon:
712  return "PCRel32Minus2Anon";
713  case PCRel32Minus4Anon:
714  return "PCRel32Minus4Anon";
715  case PCRel32GOTLoad:
716  return "PCRel32GOTLoad";
717  case PCRel32GOT:
718  return "PCRel32GOT";
719  case PCRel32TLV:
720  return "PCRel32TLV";
721  case Delta32:
722  return "Delta32";
723  case Delta64:
724  return "Delta64";
725  case NegDelta32:
726  return "NegDelta32";
727  case NegDelta64:
728  return "NegDelta64";
729  default:
730  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
731  }
732 }
733 
734 } // end namespace jitlink
735 } // end namespace llvm
detail::packed_endian_specific_integral< int64_t, little, unaligned > little64_t
Definition: Endian.h:281
This class represents lattice values for constants.
Definition: AllocatorList.h:23
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
detail::packed_endian_specific_integral< uint64_t, little, unaligned > ulittle64_t
Definition: Endian.h:274
Definition: BitVector.h:959
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:160
section_iterator_range sections() const
Definition: ObjectFile.h:319
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:42
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:272
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G)
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:305
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:45
static ErrorSuccess success()
Create a success value.
Definition: Error.h:332
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:350
static Expected< std::unique_ptr< MachOObjectFile > > createMachOObjectFile(MemoryBufferRef Object, uint32_t UniversalCputype=0, uint32_t UniversalIndex=0)
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Target - Wrapper for Target specific information.
uint64_t getSectionIndex(DataRefImpl Sec) const override
detail::packed_endian_specific_integral< int32_t, little, unaligned > little32_t
Definition: Endian.h:279
static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr, const uint64_t Size=sizeof(T))
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:152
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:521
LLVM Value Representation.
Definition: Value.h:74
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
#define LLVM_DEBUG(X)
Definition: Debug.h:122