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;
85  if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
86  return TLVPage21;
87  break;
89  if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
90  return TLVPageOffset12;
91  break;
92  }
93 
94  return make_error<JITLinkError>(
95  "Unsupported arm64 relocation: address=" +
96  formatv("{0:x8}", RI.r_address) +
97  ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
98  ", kind=" + formatv("{0:x1}", RI.r_type) +
99  ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
100  ", extern=" + (RI.r_extern ? "true" : "false") +
101  ", length=" + formatv("{0:d}", RI.r_length));
102  }
103 
104  using PairRelocInfo =
105  std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>;
106 
107  // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
108  // returns the edge kind and addend to be used.
110  parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
111  const MachO::relocation_info &SubRI,
112  orc::ExecutorAddr FixupAddress, const char *FixupContent,
113  object::relocation_iterator &UnsignedRelItr,
114  object::relocation_iterator &RelEnd) {
115  using namespace support;
116 
117  assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
118  (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
119  "Subtractor kind should match length");
120  assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
121  assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
122 
123  if (UnsignedRelItr == RelEnd)
124  return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
125  "UNSIGNED relocation");
126 
127  auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
128 
129  if (SubRI.r_address != UnsignedRI.r_address)
130  return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
131  "point to different addresses");
132 
133  if (SubRI.r_length != UnsignedRI.r_length)
134  return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
135  "UNSIGNED reloc must match");
136 
137  Symbol *FromSymbol;
138  if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
139  FromSymbol = FromSymbolOrErr->GraphSymbol;
140  else
141  return FromSymbolOrErr.takeError();
142 
143  // Read the current fixup value.
144  uint64_t FixupValue = 0;
145  if (SubRI.r_length == 3)
146  FixupValue = *(const little64_t *)FixupContent;
147  else
148  FixupValue = *(const little32_t *)FixupContent;
149 
150  // Find 'ToSymbol' using symbol number or address, depending on whether the
151  // paired UNSIGNED relocation is extern.
152  Symbol *ToSymbol = nullptr;
153  if (UnsignedRI.r_extern) {
154  // Find target symbol by symbol index.
155  if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
156  ToSymbol = ToSymbolOrErr->GraphSymbol;
157  else
158  return ToSymbolOrErr.takeError();
159  } else {
160  auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
161  if (!ToSymbolSec)
162  return ToSymbolSec.takeError();
163  ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
164  assert(ToSymbol && "No symbol for section");
165  FixupValue -= ToSymbol->getAddress().getValue();
166  }
167 
168  MachOARM64RelocationKind DeltaKind;
169  Symbol *TargetSymbol;
170  uint64_t Addend;
171  if (&BlockToFix == &FromSymbol->getAddressable()) {
172  TargetSymbol = ToSymbol;
173  DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
174  Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
175  // FIXME: handle extern 'from'.
176  } else if (&BlockToFix == &ToSymbol->getAddressable()) {
177  TargetSymbol = &*FromSymbol;
178  DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
179  Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
180  } else {
181  // BlockToFix was neither FromSymbol nor ToSymbol.
182  return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
183  "either 'A' or 'B' (or a symbol in one "
184  "of their alt-entry groups)");
185  }
186 
187  return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
188  }
189 
190  Error addRelocations() override {
191  using namespace support;
192  auto &Obj = getObject();
193 
194  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
195 
196  for (auto &S : Obj.sections()) {
197 
198  orc::ExecutorAddr SectionAddress(S.getAddress());
199 
200  // Skip relocations virtual sections.
201  if (S.isVirtual()) {
202  if (S.relocation_begin() != S.relocation_end())
203  return make_error<JITLinkError>("Virtual section contains "
204  "relocations");
205  continue;
206  }
207 
208  auto NSec =
209  findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
210  if (!NSec)
211  return NSec.takeError();
212 
213  // Skip relocations for MachO sections without corresponding graph
214  // sections.
215  {
216  if (!NSec->GraphSection) {
217  LLVM_DEBUG({
218  dbgs() << " Skipping relocations for MachO section "
219  << NSec->SegName << "/" << NSec->SectName
220  << " which has no associated graph section\n";
221  });
222  continue;
223  }
224  }
225 
226  for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
227  RelItr != RelEnd; ++RelItr) {
228 
229  MachO::relocation_info RI = getRelocationInfo(RelItr);
230 
231  // Validate the relocation kind.
232  auto Kind = getRelocationKind(RI);
233  if (!Kind)
234  return Kind.takeError();
235 
236  // Find the address of the value to fix up.
237  orc::ExecutorAddr FixupAddress =
238  SectionAddress + (uint32_t)RI.r_address;
239  LLVM_DEBUG({
240  dbgs() << " " << NSec->SectName << " + "
241  << formatv("{0:x8}", RI.r_address) << ":\n";
242  });
243 
244  // Find the block that the fixup points to.
245  Block *BlockToFix = nullptr;
246  {
247  auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
248  if (!SymbolToFixOrErr)
249  return SymbolToFixOrErr.takeError();
250  BlockToFix = &SymbolToFixOrErr->getBlock();
251  }
252 
253  if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
254  BlockToFix->getAddress() + BlockToFix->getContent().size())
255  return make_error<JITLinkError>(
256  "Relocation content extends past end of fixup block");
257 
258  // Get a pointer to the fixup content.
259  const char *FixupContent = BlockToFix->getContent().data() +
260  (FixupAddress - BlockToFix->getAddress());
261 
262  // The target symbol and addend will be populated by the switch below.
263  Symbol *TargetSymbol = nullptr;
264  uint64_t Addend = 0;
265 
266  if (*Kind == PairedAddend) {
267  // If this is an Addend relocation then process it and move to the
268  // paired reloc.
269 
270  Addend = SignExtend64(RI.r_symbolnum, 24);
271 
272  if (RelItr == RelEnd)
273  return make_error<JITLinkError>("Unpaired Addend reloc at " +
274  formatv("{0:x16}", FixupAddress));
275  ++RelItr;
276  RI = getRelocationInfo(RelItr);
277 
278  Kind = getRelocationKind(RI);
279  if (!Kind)
280  return Kind.takeError();
281 
282  if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12)
283  return make_error<JITLinkError>(
284  "Invalid relocation pair: Addend + " +
286 
287  LLVM_DEBUG({
288  dbgs() << " Addend: value = " << formatv("{0:x6}", Addend)
289  << ", pair is " << getMachOARM64RelocationKindName(*Kind)
290  << "\n";
291  });
292 
293  // Find the address of the value to fix up.
294  orc::ExecutorAddr PairedFixupAddress =
295  SectionAddress + (uint32_t)RI.r_address;
296  if (PairedFixupAddress != FixupAddress)
297  return make_error<JITLinkError>("Paired relocation points at "
298  "different target");
299  }
300 
301  switch (*Kind) {
302  case Branch26: {
303  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
304  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
305  else
306  return TargetSymbolOrErr.takeError();
307  uint32_t Instr = *(const ulittle32_t *)FixupContent;
308  if ((Instr & 0x7fffffff) != 0x14000000)
309  return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
310  "instruction with a zero addend");
311  break;
312  }
313  case Pointer32:
314  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
315  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
316  else
317  return TargetSymbolOrErr.takeError();
318  Addend = *(const ulittle32_t *)FixupContent;
319  break;
320  case Pointer64:
321  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
322  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
323  else
324  return TargetSymbolOrErr.takeError();
325  Addend = *(const ulittle64_t *)FixupContent;
326  break;
327  case Pointer64Anon: {
328  orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
329  auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
330  if (!TargetNSec)
331  return TargetNSec.takeError();
332  if (auto TargetSymbolOrErr =
333  findSymbolByAddress(*TargetNSec, TargetAddress))
334  TargetSymbol = &*TargetSymbolOrErr;
335  else
336  return TargetSymbolOrErr.takeError();
337  Addend = TargetAddress - TargetSymbol->getAddress();
338  break;
339  }
340  case Page21:
341  case TLVPage21:
342  case GOTPage21: {
343  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
344  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
345  else
346  return TargetSymbolOrErr.takeError();
347  uint32_t Instr = *(const ulittle32_t *)FixupContent;
348  if ((Instr & 0xffffffe0) != 0x90000000)
349  return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
350  "ADRP instruction with a zero "
351  "addend");
352  break;
353  }
354  case PageOffset12: {
355  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
356  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
357  else
358  return TargetSymbolOrErr.takeError();
359  uint32_t Instr = *(const ulittle32_t *)FixupContent;
360  uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
361  if (EncodedAddend != 0)
362  return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
363  "encoded addend");
364  break;
365  }
366  case TLVPageOffset12:
367  case GOTPageOffset12: {
368  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
369  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
370  else
371  return TargetSymbolOrErr.takeError();
372  uint32_t Instr = *(const ulittle32_t *)FixupContent;
373  if ((Instr & 0xfffffc00) != 0xf9400000)
374  return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
375  "immediate instruction with a zero "
376  "addend");
377  break;
378  }
379  case PointerToGOT:
380  if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
381  TargetSymbol = TargetSymbolOrErr->GraphSymbol;
382  else
383  return TargetSymbolOrErr.takeError();
384  break;
385  case Delta32:
386  case Delta64: {
387  // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
388  // parsePairRelocation handles the paired reloc, and returns the
389  // edge kind to be used (either Delta32/Delta64, or
390  // NegDelta32/NegDelta64, depending on the direction of the
391  // subtraction) along with the addend.
392  auto PairInfo =
393  parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
394  FixupContent, ++RelItr, RelEnd);
395  if (!PairInfo)
396  return PairInfo.takeError();
397  std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
398  assert(TargetSymbol && "No target symbol from parsePairRelocation?");
399  break;
400  }
401  default:
402  llvm_unreachable("Special relocation kind should not appear in "
403  "mach-o file");
404  }
405 
406  LLVM_DEBUG({
407  dbgs() << " ";
408  Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
409  Addend);
410  printEdge(dbgs(), *BlockToFix, GE,
412  dbgs() << "\n";
413  });
414  BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
415  *TargetSymbol, Addend);
416  }
417  }
418  return Error::success();
419  }
420 
421  unsigned NumSymbols = 0;
422 };
423 
424 class PerGraphGOTAndPLTStubsBuilder_MachO_arm64
426  PerGraphGOTAndPLTStubsBuilder_MachO_arm64> {
427 public:
429  PerGraphGOTAndPLTStubsBuilder_MachO_arm64>::PerGraphGOTAndPLTStubsBuilder;
430 
431  bool isGOTEdgeToFix(Edge &E) const {
432  return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
433  E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12 ||
434  E.getKind() == PointerToGOT;
435  }
436 
437  Symbol &createGOTEntry(Symbol &Target) {
438  auto &GOTEntryBlock = G.createContentBlock(
439  getGOTSection(), getGOTEntryBlockContent(), orc::ExecutorAddr(), 8, 0);
440  GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
441  return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
442  }
443 
444  void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
445  if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
446  E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12) {
447  // Update the target, but leave the edge addend as-is.
448  E.setTarget(GOTEntry);
449  } else if (E.getKind() == PointerToGOT) {
450  E.setTarget(GOTEntry);
451  E.setKind(Delta32);
452  } else
453  llvm_unreachable("Not a GOT edge?");
454  }
455 
456  bool isExternalBranchEdge(Edge &E) {
457  return E.getKind() == Branch26 && !E.getTarget().isDefined();
458  }
459 
460  Symbol &createPLTStub(Symbol &Target) {
461  auto &StubContentBlock = G.createContentBlock(
462  getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 1, 0);
463  // Re-use GOT entries for stub targets.
464  auto &GOTEntrySymbol = getGOTEntry(Target);
465  StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
466  return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
467  }
468 
469  void fixPLTEdge(Edge &E, Symbol &Stub) {
470  assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
471  assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
472  E.setTarget(Stub);
473  }
474 
475 private:
476  Section &getGOTSection() {
477  if (!GOTSection)
478  GOTSection = &G.createSection("$__GOT", MemProt::Read | MemProt::Exec);
479  return *GOTSection;
480  }
481 
482  Section &getStubsSection() {
483  if (!StubsSection)
484  StubsSection =
485  &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
486  return *StubsSection;
487  }
488 
489  ArrayRef<char> getGOTEntryBlockContent() {
490  return {reinterpret_cast<const char *>(NullGOTEntryContent),
491  sizeof(NullGOTEntryContent)};
492  }
493 
494  ArrayRef<char> getStubBlockContent() {
495  return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
496  }
497 
498  static const uint8_t NullGOTEntryContent[8];
499  static const uint8_t StubContent[8];
500  Section *GOTSection = nullptr;
501  Section *StubsSection = nullptr;
502 };
503 
504 const uint8_t
505  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = {
506  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
507 const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = {
508  0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
509  0x00, 0x02, 0x1f, 0xd6 // BR x16
510 };
511 
512 } // namespace
513 
514 namespace llvm {
515 namespace jitlink {
516 
517 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
519 
520 public:
521  MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
522  std::unique_ptr<LinkGraph> G,
523  PassConfiguration PassConfig)
524  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
525 
526 private:
527 
528  static unsigned getPageOffset12Shift(uint32_t Instr) {
529  constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
530  constexpr uint32_t Vec128Mask = 0x04800000;
531 
532  if ((Instr & LoadStoreImm12Mask) == 0x39000000) {
533  uint32_t ImplicitShift = Instr >> 30;
534  if (ImplicitShift == 0)
535  if ((Instr & Vec128Mask) == Vec128Mask)
536  ImplicitShift = 4;
537 
538  return ImplicitShift;
539  }
540 
541  return 0;
542  }
543 
544  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
545  using namespace support;
546 
547  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
548  char *FixupPtr = BlockWorkingMem + E.getOffset();
549  orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
550 
551  switch (E.getKind()) {
552  case Branch26: {
553  assert((FixupAddress.getValue() & 0x3) == 0 &&
554  "Branch-inst is not 32-bit aligned");
555 
556  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
557 
558  if (static_cast<uint64_t>(Value) & 0x3)
559  return make_error<JITLinkError>("Branch26 target is not 32-bit "
560  "aligned");
561 
562  if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
563  return makeTargetOutOfRangeError(G, B, E);
564 
565  uint32_t RawInstr = *(little32_t *)FixupPtr;
566  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
567  "RawInstr isn't a B or BR immediate instruction");
568  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
569  uint32_t FixedInstr = RawInstr | Imm;
570  *(little32_t *)FixupPtr = FixedInstr;
571  break;
572  }
573  case Pointer32: {
574  uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
576  return makeTargetOutOfRangeError(G, B, E);
577  *(ulittle32_t *)FixupPtr = Value;
578  break;
579  }
580  case Pointer64:
581  case Pointer64Anon: {
582  uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
583  *(ulittle64_t *)FixupPtr = Value;
584  break;
585  }
586  case Page21:
587  case TLVPage21:
588  case GOTPage21: {
589  assert((E.getKind() != GOTPage21 || E.getAddend() == 0) &&
590  "GOTPAGE21 with non-zero addend");
591  uint64_t TargetPage =
592  (E.getTarget().getAddress().getValue() + E.getAddend()) &
593  ~static_cast<uint64_t>(4096 - 1);
594  uint64_t PCPage =
595  FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1);
596 
597  int64_t PageDelta = TargetPage - PCPage;
598  if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
599  return makeTargetOutOfRangeError(G, B, E);
600 
601  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
602  assert((RawInstr & 0xffffffe0) == 0x90000000 &&
603  "RawInstr isn't an ADRP instruction");
604  uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
605  uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
606  uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
607  *(ulittle32_t *)FixupPtr = FixedInstr;
608  break;
609  }
610  case PageOffset12: {
611  uint64_t TargetOffset =
612  (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff;
613 
614  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
615  unsigned ImmShift = getPageOffset12Shift(RawInstr);
616 
617  if (TargetOffset & ((1 << ImmShift) - 1))
618  return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
619 
620  uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
621  uint32_t FixedInstr = RawInstr | EncodedImm;
622  *(ulittle32_t *)FixupPtr = FixedInstr;
623  break;
624  }
625  case TLVPageOffset12:
626  case GOTPageOffset12: {
627  assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
628 
629  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
630  assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
631  "RawInstr isn't a 64-bit LDR immediate");
632 
633  uint32_t TargetOffset = E.getTarget().getAddress().getValue() & 0xfff;
634  assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
635  uint32_t EncodedImm = (TargetOffset >> 3) << 10;
636  uint32_t FixedInstr = RawInstr | EncodedImm;
637  *(ulittle32_t *)FixupPtr = FixedInstr;
638  break;
639  }
640  case LDRLiteral19: {
641  assert((FixupAddress.getValue() & 0x3) == 0 &&
642  "LDR is not 32-bit aligned");
643  assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
644  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
645  assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
646  int64_t Delta = E.getTarget().getAddress() - FixupAddress;
647  if (Delta & 0x3)
648  return make_error<JITLinkError>("LDR literal target is not 32-bit "
649  "aligned");
650  if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
651  return makeTargetOutOfRangeError(G, B, E);
652 
653  uint32_t EncodedImm =
654  ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
655  uint32_t FixedInstr = RawInstr | EncodedImm;
656  *(ulittle32_t *)FixupPtr = FixedInstr;
657  break;
658  }
659  case Delta32:
660  case Delta64:
661  case NegDelta32:
662  case NegDelta64: {
663  int64_t Value;
664  if (E.getKind() == Delta32 || E.getKind() == Delta64)
665  Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
666  else
667  Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
668 
669  if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
672  return makeTargetOutOfRangeError(G, B, E);
673  *(little32_t *)FixupPtr = Value;
674  } else
675  *(little64_t *)FixupPtr = Value;
676  break;
677  }
678  default:
679  llvm_unreachable("Unrecognized edge kind");
680  }
681 
682  return Error::success();
683  }
684 
685  uint64_t NullValue = 0;
686 };
687 
690  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
691  if (!MachOObj)
692  return MachOObj.takeError();
693  return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
694 }
695 
696 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
697  std::unique_ptr<JITLinkContext> Ctx) {
698 
699  PassConfiguration Config;
700 
701  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
702  // Add a mark-live pass.
703  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
704  Config.PrePrunePasses.push_back(std::move(MarkLive));
705  else
706  Config.PrePrunePasses.push_back(markAllSymbolsLive);
707 
708  // Add compact unwind splitter pass.
709  Config.PrePrunePasses.push_back(
710  CompactUnwindSplitter("__LD,__compact_unwind"));
711 
712  // Add eh-frame passses.
713  // FIXME: Prune eh-frames for which compact-unwind is available once
714  // we support compact-unwind registration with libunwind.
715  Config.PrePrunePasses.push_back(EHFrameSplitter("__TEXT,__eh_frame"));
716  Config.PrePrunePasses.push_back(
717  EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Delta64, Delta32, NegDelta32));
718 
719  // Add an in-place GOT/Stubs pass.
720  Config.PostPrunePasses.push_back(
721  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
722  }
723 
724  if (auto Err = Ctx->modifyPassConfig(*G, Config))
725  return Ctx->notifyFailed(std::move(Err));
726 
727  // Construct a JITLinker and run the link function.
729 }
730 
732  switch (R) {
733  case Branch26:
734  return "Branch26";
735  case Pointer64:
736  return "Pointer64";
737  case Pointer64Anon:
738  return "Pointer64Anon";
739  case Page21:
740  return "Page21";
741  case PageOffset12:
742  return "PageOffset12";
743  case GOTPage21:
744  return "GOTPage21";
745  case GOTPageOffset12:
746  return "GOTPageOffset12";
747  case TLVPage21:
748  return "TLVPage21";
749  case TLVPageOffset12:
750  return "TLVPageOffset12";
751  case PointerToGOT:
752  return "PointerToGOT";
753  case PairedAddend:
754  return "PairedAddend";
755  case LDRLiteral19:
756  return "LDRLiteral19";
757  case Delta32:
758  return "Delta32";
759  case Delta64:
760  return "Delta64";
761  case NegDelta32:
762  return "NegDelta32";
763  case NegDelta64:
764  return "NegDelta64";
765  default:
766  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
767  }
768 }
769 
770 } // end namespace jitlink
771 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:30
llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12
@ ARM64_RELOC_TLVP_LOAD_PAGEOFF12
Definition: MachO.h:467
llvm::MachO::ARM64_RELOC_UNSIGNED
@ ARM64_RELOC_UNSIGNED
Definition: MachO.h:449
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::MachO::relocation_info::r_length
uint32_t r_length
Definition: MachO.h:960
llvm::object::MachOObjectFile::getSectionIndex
uint64_t getSectionIndex(DataRefImpl Sec) const override
Definition: MachOObjectFile.cpp:1926
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:4700
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:959
llvm::Triple
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
llvm::orc::ExecutorAddr::getValue
uint64_t getValue() const
Definition: ExecutorAddress.h:53
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:698
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::ArrayRef::data
const T * data() const
Definition: ArrayRef.h:160
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:207
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:958
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:961
llvm::MachO::relocation_info::r_extern
uint32_t r_extern
Definition: MachO.h:960
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:1707
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:57
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:4522
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:163
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:321
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:960
MachOLinkGraphBuilder.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::X86II::ImmShift
@ ImmShift
Definition: X86BaseInfo.h:843
llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21
@ ARM64_RELOC_TLVP_LOAD_PAGE21
Definition: MachO.h:465
llvm::MachO::relocation_info::r_symbolnum
uint32_t r_symbolnum
Definition: MachO.h:960