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