LLVM  14.0.0git
MachO_arm64.cpp
Go to the documentation of this file.
1 //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===//
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/arm64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
15 #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_arm64_Edges;
23 
24 namespace {
25 
26 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
27 public:
28  MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
29  : MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin"),
31  NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
32 
33 private:
35  getRelocationKind(const MachO::relocation_info &RI) {
36  switch (RI.r_type) {
38  if (!RI.r_pcrel) {
39  if (RI.r_length == 3)
40  return RI.r_extern ? Pointer64 : Pointer64Anon;
41  else if (RI.r_length == 2)
42  return Pointer32;
43  }
44  break;
46  // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
47  // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
48  // They may be turned into NegDelta<W> by parsePairRelocation.
49  if (!RI.r_pcrel && RI.r_extern) {
50  if (RI.r_length == 2)
51  return Delta32;
52  else if (RI.r_length == 3)
53  return Delta64;
54  }
55  break;
57  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
58  return Branch26;
59  break;
61  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
62  return Page21;
63  break;
65  if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
66  return PageOffset12;
67  break;
69  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
70  return GOTPage21;
71  break;
73  if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
74  return GOTPageOffset12;
75  break;
77  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
78  return PointerToGOT;
79  break;
81  if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
82  return PairedAddend;
83  break;
84  }
85 
86  return make_error<JITLinkError>(
87  "Unsupported arm64 relocation: address=" +
88  formatv("{0:x8}", RI.r_address) +
89  ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
90  ", kind=" + formatv("{0:x1}", RI.r_type) +
91  ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
92  ", extern=" + (RI.r_extern ? "true" : "false") +
93  ", length=" + formatv("{0:d}", RI.r_length));
94  }
95 
96  using PairRelocInfo =
97  std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>;
98 
99  // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
100  // returns the edge kind and addend to be used.
102  parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
103  const MachO::relocation_info &SubRI,
104  JITTargetAddress FixupAddress, const char *FixupContent,
105  object::relocation_iterator &UnsignedRelItr,
106  object::relocation_iterator &RelEnd) {
107  using namespace support;
108 
109  assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
110  (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
111  "Subtractor kind should match length");
112  assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
113  assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
114 
115  if (UnsignedRelItr == RelEnd)
116  return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
117  "UNSIGNED relocation");
118 
119  auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
120 
121  if (SubRI.r_address != UnsignedRI.r_address)
122  return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
123  "point to different addresses");
124 
125  if (SubRI.r_length != UnsignedRI.r_length)
126  return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
127  "UNSIGNED reloc must match");
128 
129  Symbol *FromSymbol;
130  if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
131  FromSymbol = FromSymbolOrErr->GraphSymbol;
132  else
133  return FromSymbolOrErr.takeError();
134 
135  // Read the current fixup value.
136  uint64_t FixupValue = 0;
137  if (SubRI.r_length == 3)
138  FixupValue = *(const little64_t *)FixupContent;
139  else
140  FixupValue = *(const little32_t *)FixupContent;
141 
142  // Find 'ToSymbol' using symbol number or address, depending on whether the
143  // paired UNSIGNED relocation is extern.
144  Symbol *ToSymbol = nullptr;
145  if (UnsignedRI.r_extern) {
146  // Find target symbol by symbol index.
147  if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
148  ToSymbol = ToSymbolOrErr->GraphSymbol;
149  else
150  return ToSymbolOrErr.takeError();
151  } else {
152  auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
153  if (!ToSymbolSec)
154  return ToSymbolSec.takeError();
155  ToSymbol = getSymbolByAddress(ToSymbolSec->Address);
156  assert(ToSymbol && "No symbol for section");
157  FixupValue -= ToSymbol->getAddress();
158  }
159 
160  MachOARM64RelocationKind 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 groups)");
177  }
178 
179  return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
180  }
181 
182  Error addRelocations() override {
183  using namespace support;
184  auto &Obj = getObject();
185 
186  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
187 
188  for (auto &S : Obj.sections()) {
189 
190  JITTargetAddress SectionAddress = S.getAddress();
191 
192  // Skip relocations virtual sections.
193  if (S.isVirtual()) {
194  if (S.relocation_begin() != S.relocation_end())
195  return make_error<JITLinkError>("Virtual section contains "
196  "relocations");
197  continue;
198  }
199 
200  // Skip relocations for debug symbols.
201  {
202  auto &NSec =
203  getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
204  if (!NSec.GraphSection) {
205  LLVM_DEBUG({
206  dbgs() << " Skipping relocations for MachO section "
207  << NSec.SegName << "/" << NSec.SectName
208  << " which has no associated graph section\n";
209  });
210  continue;
211  }
212  }
213 
214  for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
215  RelItr != RelEnd; ++RelItr) {
216 
217  MachO::relocation_info RI = getRelocationInfo(RelItr);
218 
219  // Sanity check the relocation kind.
220  auto Kind = getRelocationKind(RI);
221  if (!Kind)
222  return Kind.takeError();
223 
224  // Find the address of the value to fix up.
225  JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
226 
227  LLVM_DEBUG({
228  auto &NSec =
229  getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
230  dbgs() << " " << NSec.SectName << " + "
231  << formatv("{0:x8}", RI.r_address) << ":\n";
232  });
233 
234  // Find the block that the fixup points to.
235  Block *BlockToFix = nullptr;
236  {
237  auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
238  if (!SymbolToFixOrErr)
239  return SymbolToFixOrErr.takeError();
240  BlockToFix = &SymbolToFixOrErr->getBlock();
241  }
242 
243  if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
244  BlockToFix->getAddress() + BlockToFix->getContent().size())
245  return make_error<JITLinkError>(
246  "Relocation content extends past end of fixup block");
247 
248  // Get a pointer to the fixup content.
249  const char *FixupContent = BlockToFix->getContent().data() +
250  (FixupAddress - BlockToFix->getAddress());
251 
252  // The target symbol and addend will be populated by the switch below.
253  Symbol *TargetSymbol = nullptr;
254  uint64_t Addend = 0;
255 
256  if (*Kind == PairedAddend) {
257  // If this is an Addend relocation then process it and move to the
258  // paired reloc.
259 
260  Addend = SignExtend64(RI.r_symbolnum, 24);
261 
262  if (RelItr == RelEnd)
263  return make_error<JITLinkError>("Unpaired Addend reloc at " +
264  formatv("{0:x16}", FixupAddress));
265  ++RelItr;
266  RI = getRelocationInfo(RelItr);
267 
268  Kind = getRelocationKind(RI);
269  if (!Kind)
270  return Kind.takeError();
271 
272  if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12)
273  return make_error<JITLinkError>(
274  "Invalid relocation pair: Addend + " +
276 
277  LLVM_DEBUG({
278  dbgs() << " Addend: value = " << formatv("{0:x6}", Addend)
279  << ", pair is " << getMachOARM64RelocationKindName(*Kind)
280  << "\n";
281  });
282 
283  // Find the address of the value to fix up.
284  JITTargetAddress PairedFixupAddress =
285  SectionAddress + (uint32_t)RI.r_address;
286  if (PairedFixupAddress != FixupAddress)
287  return make_error<JITLinkError>("Paired relocation points at "
288  "different target");
289  }
290 
291  switch (*Kind) {
292  case Branch26: {
293  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
294  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
295  else
296  return TargetSymbolOrErr.takeError();
297  uint32_t Instr = *(const ulittle32_t *)FixupContent;
298  if ((Instr & 0x7fffffff) != 0x14000000)
299  return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
300  "instruction with a zero addend");
301  break;
302  }
303  case Pointer32:
304  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
305  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
306  else
307  return TargetSymbolOrErr.takeError();
308  Addend = *(const ulittle32_t *)FixupContent;
309  break;
310  case Pointer64:
311  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
312  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
313  else
314  return TargetSymbolOrErr.takeError();
315  Addend = *(const ulittle64_t *)FixupContent;
316  break;
317  case Pointer64Anon: {
318  JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
319  if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
320  TargetSymbol = &*TargetSymbolOrErr;
321  else
322  return TargetSymbolOrErr.takeError();
323  Addend = TargetAddress - TargetSymbol->getAddress();
324  break;
325  }
326  case Page21:
327  case GOTPage21: {
328  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
329  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
330  else
331  return TargetSymbolOrErr.takeError();
332  uint32_t Instr = *(const ulittle32_t *)FixupContent;
333  if ((Instr & 0xffffffe0) != 0x90000000)
334  return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
335  "ADRP instruction with a zero "
336  "addend");
337  break;
338  }
339  case PageOffset12: {
340  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
341  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
342  else
343  return TargetSymbolOrErr.takeError();
344  uint32_t Instr = *(const ulittle32_t *)FixupContent;
345  uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
346  if (EncodedAddend != 0)
347  return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
348  "encoded addend");
349  break;
350  }
351  case GOTPageOffset12: {
352  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
353  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
354  else
355  return TargetSymbolOrErr.takeError();
356  uint32_t Instr = *(const ulittle32_t *)FixupContent;
357  if ((Instr & 0xfffffc00) != 0xf9400000)
358  return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
359  "immediate instruction with a zero "
360  "addend");
361  break;
362  }
363  case PointerToGOT:
364  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
365  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
366  else
367  return TargetSymbolOrErr.takeError();
368  break;
369  case Delta32:
370  case Delta64: {
371  // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
372  // parsePairRelocation handles the paired reloc, and returns the
373  // edge kind to be used (either Delta32/Delta64, or
374  // NegDelta32/NegDelta64, depending on the direction of the
375  // subtraction) along with the addend.
376  auto PairInfo =
377  parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
378  FixupContent, ++RelItr, RelEnd);
379  if (!PairInfo)
380  return PairInfo.takeError();
381  std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
382  assert(TargetSymbol && "No target symbol from parsePairRelocation?");
383  break;
384  }
385  default:
386  llvm_unreachable("Special relocation kind should not appear in "
387  "mach-o file");
388  }
389 
390  LLVM_DEBUG({
391  dbgs() << " ";
392  Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
393  Addend);
394  printEdge(dbgs(), *BlockToFix, GE,
396  dbgs() << "\n";
397  });
398  BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
399  *TargetSymbol, Addend);
400  }
401  }
402  return Error::success();
403  }
404 
405  unsigned NumSymbols = 0;
406 };
407 
408 class PerGraphGOTAndPLTStubsBuilder_MachO_arm64
410  PerGraphGOTAndPLTStubsBuilder_MachO_arm64> {
411 public:
413  PerGraphGOTAndPLTStubsBuilder_MachO_arm64>::PerGraphGOTAndPLTStubsBuilder;
414 
415  bool isGOTEdgeToFix(Edge &E) const {
416  return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
417  E.getKind() == PointerToGOT;
418  }
419 
420  Symbol &createGOTEntry(Symbol &Target) {
421  auto &GOTEntryBlock = G.createContentBlock(
422  getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
423  GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
424  return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
425  }
426 
427  void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
428  if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12) {
429  // Update the target, but leave the edge addend as-is.
430  E.setTarget(GOTEntry);
431  } else if (E.getKind() == PointerToGOT) {
432  E.setTarget(GOTEntry);
433  E.setKind(Delta32);
434  } else
435  llvm_unreachable("Not a GOT edge?");
436  }
437 
438  bool isExternalBranchEdge(Edge &E) {
439  return E.getKind() == Branch26 && !E.getTarget().isDefined();
440  }
441 
442  Symbol &createPLTStub(Symbol &Target) {
443  auto &StubContentBlock =
444  G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
445  // Re-use GOT entries for stub targets.
446  auto &GOTEntrySymbol = getGOTEntry(Target);
447  StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
448  return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
449  }
450 
451  void fixPLTEdge(Edge &E, Symbol &Stub) {
452  assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
453  assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
454  E.setTarget(Stub);
455  }
456 
457 private:
458  Section &getGOTSection() {
459  if (!GOTSection)
460  GOTSection = &G.createSection("$__GOT", MemProt::Read);
461  return *GOTSection;
462  }
463 
464  Section &getStubsSection() {
465  if (!StubsSection)
466  StubsSection =
467  &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
468  return *StubsSection;
469  }
470 
471  ArrayRef<char> getGOTEntryBlockContent() {
472  return {reinterpret_cast<const char *>(NullGOTEntryContent),
473  sizeof(NullGOTEntryContent)};
474  }
475 
476  ArrayRef<char> getStubBlockContent() {
477  return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
478  }
479 
480  static const uint8_t NullGOTEntryContent[8];
481  static const uint8_t StubContent[8];
482  Section *GOTSection = nullptr;
483  Section *StubsSection = nullptr;
484 };
485 
486 const uint8_t
487  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = {
488  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
489 const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = {
490  0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
491  0x00, 0x02, 0x1f, 0xd6 // BR x16
492 };
493 
494 } // namespace
495 
496 namespace llvm {
497 namespace jitlink {
498 
499 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
501 
502 public:
503  MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
504  std::unique_ptr<LinkGraph> G,
505  PassConfiguration PassConfig)
506  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
507 
508 private:
509 
510  static unsigned getPageOffset12Shift(uint32_t Instr) {
511  constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
512  constexpr uint32_t Vec128Mask = 0x04800000;
513 
514  if ((Instr & LoadStoreImm12Mask) == 0x39000000) {
515  uint32_t ImplicitShift = Instr >> 30;
516  if (ImplicitShift == 0)
517  if ((Instr & Vec128Mask) == Vec128Mask)
518  ImplicitShift = 4;
519 
520  return ImplicitShift;
521  }
522 
523  return 0;
524  }
525 
526  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
527  using namespace support;
528 
529  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
530  char *FixupPtr = BlockWorkingMem + E.getOffset();
531  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
532 
533  switch (E.getKind()) {
534  case Branch26: {
535  assert((FixupAddress & 0x3) == 0 && "Branch-inst is not 32-bit aligned");
536 
537  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
538 
539  if (static_cast<uint64_t>(Value) & 0x3)
540  return make_error<JITLinkError>("Branch26 target is not 32-bit "
541  "aligned");
542 
543  if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
544  return makeTargetOutOfRangeError(G, B, E);
545 
546  uint32_t RawInstr = *(little32_t *)FixupPtr;
547  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
548  "RawInstr isn't a B or BR immediate instruction");
549  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
550  uint32_t FixedInstr = RawInstr | Imm;
551  *(little32_t *)FixupPtr = FixedInstr;
552  break;
553  }
554  case Pointer32: {
555  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
557  return makeTargetOutOfRangeError(G, B, E);
558  *(ulittle32_t *)FixupPtr = Value;
559  break;
560  }
561  case Pointer64:
562  case Pointer64Anon: {
563  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
564  *(ulittle64_t *)FixupPtr = Value;
565  break;
566  }
567  case Page21:
568  case GOTPage21: {
569  assert((E.getKind() != GOTPage21 || E.getAddend() == 0) &&
570  "GOTPAGE21 with non-zero addend");
571  uint64_t TargetPage =
572  (E.getTarget().getAddress() + E.getAddend()) &
573  ~static_cast<uint64_t>(4096 - 1);
574  uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(4096 - 1);
575 
576  int64_t PageDelta = TargetPage - PCPage;
577  if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
578  return makeTargetOutOfRangeError(G, B, E);
579 
580  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
581  assert((RawInstr & 0xffffffe0) == 0x90000000 &&
582  "RawInstr isn't an ADRP instruction");
583  uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
584  uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
585  uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
586  *(ulittle32_t *)FixupPtr = FixedInstr;
587  break;
588  }
589  case PageOffset12: {
590  uint64_t TargetOffset =
591  (E.getTarget().getAddress() + E.getAddend()) & 0xfff;
592 
593  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
594  unsigned ImmShift = getPageOffset12Shift(RawInstr);
595 
596  if (TargetOffset & ((1 << ImmShift) - 1))
597  return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
598 
599  uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
600  uint32_t FixedInstr = RawInstr | EncodedImm;
601  *(ulittle32_t *)FixupPtr = FixedInstr;
602  break;
603  }
604  case GOTPageOffset12: {
605  assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
606 
607  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
608  assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
609  "RawInstr isn't a 64-bit LDR immediate");
610 
611  uint32_t TargetOffset = E.getTarget().getAddress() & 0xfff;
612  assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
613  uint32_t EncodedImm = (TargetOffset >> 3) << 10;
614  uint32_t FixedInstr = RawInstr | EncodedImm;
615  *(ulittle32_t *)FixupPtr = FixedInstr;
616  break;
617  }
618  case LDRLiteral19: {
619  assert((FixupAddress & 0x3) == 0 && "LDR is not 32-bit aligned");
620  assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
621  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
622  assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
623  int64_t Delta = E.getTarget().getAddress() - FixupAddress;
624  if (Delta & 0x3)
625  return make_error<JITLinkError>("LDR literal target is not 32-bit "
626  "aligned");
627  if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
628  return makeTargetOutOfRangeError(G, B, E);
629 
630  uint32_t EncodedImm =
631  ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
632  uint32_t FixedInstr = RawInstr | EncodedImm;
633  *(ulittle32_t *)FixupPtr = FixedInstr;
634  break;
635  }
636  case Delta32:
637  case Delta64:
638  case NegDelta32:
639  case NegDelta64: {
640  int64_t Value;
641  if (E.getKind() == Delta32 || E.getKind() == Delta64)
642  Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
643  else
644  Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
645 
646  if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
649  return makeTargetOutOfRangeError(G, B, E);
650  *(little32_t *)FixupPtr = Value;
651  } else
652  *(little64_t *)FixupPtr = Value;
653  break;
654  }
655  default:
656  llvm_unreachable("Unrecognized edge kind");
657  }
658 
659  return Error::success();
660  }
661 
662  uint64_t NullValue = 0;
663 };
664 
667  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
668  if (!MachOObj)
669  return MachOObj.takeError();
670  return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
671 }
672 
673 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
674  std::unique_ptr<JITLinkContext> Ctx) {
675 
676  PassConfiguration Config;
677 
678  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
679  // Add a mark-live pass.
680  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
681  Config.PrePrunePasses.push_back(std::move(MarkLive));
682  else
683  Config.PrePrunePasses.push_back(markAllSymbolsLive);
684 
685  // Add compact unwind splitter pass.
686  Config.PrePrunePasses.push_back(
687  CompactUnwindSplitter("__LD,__compact_unwind"));
688 
689  // Add an in-place GOT/Stubs pass.
690  Config.PostPrunePasses.push_back(
691  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
692  }
693 
694  if (auto Err = Ctx->modifyPassConfig(*G, Config))
695  return Ctx->notifyFailed(std::move(Err));
696 
697  // Construct a JITLinker and run the link function.
699 }
700 
702  switch (R) {
703  case Branch26:
704  return "Branch26";
705  case Pointer64:
706  return "Pointer64";
707  case Pointer64Anon:
708  return "Pointer64Anon";
709  case Page21:
710  return "Page21";
711  case PageOffset12:
712  return "PageOffset12";
713  case GOTPage21:
714  return "GOTPage21";
715  case GOTPageOffset12:
716  return "GOTPageOffset12";
717  case PointerToGOT:
718  return "PointerToGOT";
719  case PairedAddend:
720  return "PairedAddend";
721  case LDRLiteral19:
722  return "LDRLiteral19";
723  case Delta32:
724  return "Delta32";
725  case Delta64:
726  return "Delta64";
727  case NegDelta32:
728  return "NegDelta32";
729  case NegDelta64:
730  return "NegDelta64";
731  default:
732  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
733  }
734 }
735 
736 } // end namespace jitlink
737 } // end namespace llvm
llvm::MachO::ARM64_RELOC_UNSIGNED
@ ARM64_RELOC_UNSIGNED
Definition: MachO.h:449
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
llvm::MachO::relocation_info::r_length
uint32_t r_length
Definition: MachO.h:959
llvm::X86II::ImmShift
@ ImmShift
Definition: X86BaseInfo.h:838
llvm::object::MachOObjectFile::getSectionIndex
uint64_t getSectionIndex(DataRefImpl Sec) const override
Definition: MachOObjectFile.cpp:1923
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:137
llvm::MachO::ARM64_RELOC_BRANCH26
@ ARM64_RELOC_BRANCH26
Definition: MachO.h:453
llvm::object::ObjectFile::createMachOObjectFile
static Expected< std::unique_ptr< MachOObjectFile > > createMachOObjectFile(MemoryBufferRef Object, uint32_t UniversalCputype=0, uint32_t UniversalIndex=0)
Definition: MachOObjectFile.cpp:4657
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::MachO::ARM64_RELOC_ADDEND
@ ARM64_RELOC_ADDEND
Definition: MachO.h:469
llvm::MachO::relocation_info::r_address
int32_t r_address
Definition: MachO.h:958
llvm::Triple
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:45
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::MemoryBufferRef
Definition: MemoryBufferRef.h:22
llvm::MachO::symtab_command::nsyms
uint32_t nsyms
Definition: MachO.h:697
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::ArrayRef::data
const T * data() const
Definition: ArrayRef.h:162
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:198
llvm::MachO::ARM64_RELOC_SUBTRACTOR
@ ARM64_RELOC_SUBTRACTOR
Definition: MachO.h:451
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
x3
In x86 we generate this spiffy xmm0 xmm0 ret in x86 we generate this which could be xmm1 movss xmm1 xmm0 ret In sse4 we could use insertps to make both better Here s another testcase that could use x3
Definition: README-SSE.txt:547
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::lltok::Kind
Kind
Definition: LLToken.h:18
llvm::object::MachOObjectFile
Definition: MachO.h:262
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::MachO::relocation_info
Definition: MachO.h:957
uint64_t
llvm::MachO::ARM64_RELOC_PAGE21
@ ARM64_RELOC_PAGE21
Definition: MachO.h:455
llvm::MachO::relocation_info::r_type
uint32_t r_type
Definition: MachO.h:960
llvm::MachO::relocation_info::r_extern
uint32_t r_extern
Definition: MachO.h:959
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1609
MachO_arm64.h
llvm::object::content_iterator
Definition: SymbolicFile.h:67
llvm::MachO::ARM64_RELOC_POINTER_TO_GOT
@ ARM64_RELOC_POINTER_TO_GOT
Definition: MachO.h:463
llvm::AArch64CC::GE
@ GE
Definition: AArch64BaseInfo.h:265
llvm::ArrayRef< char >
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:58
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
if
if(llvm_vc STREQUAL "") set(fake_version_inc "$
Definition: CMakeLists.txt:14
uint32_t
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::SignExtend64
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition: MathExtras.h:777
PerGraphGOTAndPLTStubsBuilder.h
llvm::object::MachOObjectFile::getSymtabLoadCommand
MachO::symtab_command getSymtabLoadCommand() const
Definition: MachOObjectFile.cpp:4479
std
Definition: BitVector.h:838
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
getObject
static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr, const uint64_t Size=sizeof(T))
Definition: COFFObjectFile.cpp:58
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
llvm::MachO::ARM64_RELOC_PAGEOFF12
@ ARM64_RELOC_PAGEOFF12
Definition: MachO.h:457
llvm::support::ulittle64_t
detail::packed_endian_specific_integral< uint64_t, little, unaligned > ulittle64_t
Definition: Endian.h:274
llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21
@ ARM64_RELOC_GOT_LOAD_PAGE21
Definition: MachO.h:459
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
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::object::ObjectFile::sections
section_iterator_range sections() const
Definition: ObjectFile.h:322
llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12
@ ARM64_RELOC_GOT_LOAD_PAGEOFF12
Definition: MachO.h:461
llvm::MachO::relocation_info::r_pcrel
uint32_t r_pcrel
Definition: MachO.h:959
MachOLinkGraphBuilder.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::MachO::relocation_info::r_symbolnum
uint32_t r_symbolnum
Definition: MachO.h:959