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", sys::Memory::MF_READ);
461  return *GOTSection;
462  }
463 
464  Section &getStubsSection() {
465  if (!StubsSection) {
466  auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
468  StubsSection = &G.createSection("$__STUBS", StubsProt);
469  }
470  return *StubsSection;
471  }
472 
473  ArrayRef<char> getGOTEntryBlockContent() {
474  return {reinterpret_cast<const char *>(NullGOTEntryContent),
475  sizeof(NullGOTEntryContent)};
476  }
477 
478  ArrayRef<char> getStubBlockContent() {
479  return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
480  }
481 
482  static const uint8_t NullGOTEntryContent[8];
483  static const uint8_t StubContent[8];
484  Section *GOTSection = nullptr;
485  Section *StubsSection = nullptr;
486 };
487 
488 const uint8_t
489  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = {
490  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
491 const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = {
492  0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
493  0x00, 0x02, 0x1f, 0xd6 // BR x16
494 };
495 
496 } // namespace
497 
498 namespace llvm {
499 namespace jitlink {
500 
501 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
503 
504 public:
505  MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
506  std::unique_ptr<LinkGraph> G,
507  PassConfiguration PassConfig)
508  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
509 
510 private:
511 
512  static unsigned getPageOffset12Shift(uint32_t Instr) {
513  constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
514  constexpr uint32_t Vec128Mask = 0x04800000;
515 
516  if ((Instr & LoadStoreImm12Mask) == 0x39000000) {
517  uint32_t ImplicitShift = Instr >> 30;
518  if (ImplicitShift == 0)
519  if ((Instr & Vec128Mask) == Vec128Mask)
520  ImplicitShift = 4;
521 
522  return ImplicitShift;
523  }
524 
525  return 0;
526  }
527 
528  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
529  using namespace support;
530 
531  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
532  char *FixupPtr = BlockWorkingMem + E.getOffset();
533  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
534 
535  switch (E.getKind()) {
536  case Branch26: {
537  assert((FixupAddress & 0x3) == 0 && "Branch-inst is not 32-bit aligned");
538 
539  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
540 
541  if (static_cast<uint64_t>(Value) & 0x3)
542  return make_error<JITLinkError>("Branch26 target is not 32-bit "
543  "aligned");
544 
545  if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
546  return makeTargetOutOfRangeError(G, B, E);
547 
548  uint32_t RawInstr = *(little32_t *)FixupPtr;
549  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
550  "RawInstr isn't a B or BR immediate instruction");
551  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
552  uint32_t FixedInstr = RawInstr | Imm;
553  *(little32_t *)FixupPtr = FixedInstr;
554  break;
555  }
556  case Pointer32: {
557  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
559  return makeTargetOutOfRangeError(G, B, E);
560  *(ulittle32_t *)FixupPtr = Value;
561  break;
562  }
563  case Pointer64:
564  case Pointer64Anon: {
565  uint64_t Value = E.getTarget().getAddress() + E.getAddend();
566  *(ulittle64_t *)FixupPtr = Value;
567  break;
568  }
569  case Page21:
570  case GOTPage21: {
571  assert((E.getKind() != GOTPage21 || E.getAddend() == 0) &&
572  "GOTPAGE21 with non-zero addend");
573  uint64_t TargetPage =
574  (E.getTarget().getAddress() + E.getAddend()) &
575  ~static_cast<uint64_t>(4096 - 1);
576  uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(4096 - 1);
577 
578  int64_t PageDelta = TargetPage - PCPage;
579  if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
580  return makeTargetOutOfRangeError(G, B, E);
581 
582  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
583  assert((RawInstr & 0xffffffe0) == 0x90000000 &&
584  "RawInstr isn't an ADRP instruction");
585  uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
586  uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
587  uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
588  *(ulittle32_t *)FixupPtr = FixedInstr;
589  break;
590  }
591  case PageOffset12: {
592  uint64_t TargetOffset =
593  (E.getTarget().getAddress() + E.getAddend()) & 0xfff;
594 
595  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
596  unsigned ImmShift = getPageOffset12Shift(RawInstr);
597 
598  if (TargetOffset & ((1 << ImmShift) - 1))
599  return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
600 
601  uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
602  uint32_t FixedInstr = RawInstr | EncodedImm;
603  *(ulittle32_t *)FixupPtr = FixedInstr;
604  break;
605  }
606  case GOTPageOffset12: {
607  assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
608 
609  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
610  assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
611  "RawInstr isn't a 64-bit LDR immediate");
612 
613  uint32_t TargetOffset = E.getTarget().getAddress() & 0xfff;
614  assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
615  uint32_t EncodedImm = (TargetOffset >> 3) << 10;
616  uint32_t FixedInstr = RawInstr | EncodedImm;
617  *(ulittle32_t *)FixupPtr = FixedInstr;
618  break;
619  }
620  case LDRLiteral19: {
621  assert((FixupAddress & 0x3) == 0 && "LDR is not 32-bit aligned");
622  assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
623  uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
624  assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
625  int64_t Delta = E.getTarget().getAddress() - FixupAddress;
626  if (Delta & 0x3)
627  return make_error<JITLinkError>("LDR literal target is not 32-bit "
628  "aligned");
629  if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
630  return makeTargetOutOfRangeError(G, B, E);
631 
632  uint32_t EncodedImm = (static_cast<uint32_t>(Delta) >> 2) << 5;
633  uint32_t FixedInstr = RawInstr | EncodedImm;
634  *(ulittle32_t *)FixupPtr = FixedInstr;
635  break;
636  }
637  case Delta32:
638  case Delta64:
639  case NegDelta32:
640  case NegDelta64: {
641  int64_t Value;
642  if (E.getKind() == Delta32 || E.getKind() == Delta64)
643  Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
644  else
645  Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
646 
647  if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
650  return makeTargetOutOfRangeError(G, B, E);
651  *(little32_t *)FixupPtr = Value;
652  } else
653  *(little64_t *)FixupPtr = Value;
654  break;
655  }
656  default:
657  llvm_unreachable("Unrecognized edge kind");
658  }
659 
660  return Error::success();
661  }
662 
663  uint64_t NullValue = 0;
664 };
665 
668  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
669  if (!MachOObj)
670  return MachOObj.takeError();
671  return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
672 }
673 
674 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
675  std::unique_ptr<JITLinkContext> Ctx) {
676 
677  PassConfiguration Config;
678 
679  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
680  // Add a mark-live pass.
681  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
682  Config.PrePrunePasses.push_back(std::move(MarkLive));
683  else
684  Config.PrePrunePasses.push_back(markAllSymbolsLive);
685 
686  // Add an in-place GOT/Stubs pass.
687  Config.PostPrunePasses.push_back(
688  PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
689  }
690 
691  if (auto Err = Ctx->modifyPassConfig(*G, Config))
692  return Ctx->notifyFailed(std::move(Err));
693 
694  // Construct a JITLinker and run the link function.
696 }
697 
699  switch (R) {
700  case Branch26:
701  return "Branch26";
702  case Pointer64:
703  return "Pointer64";
704  case Pointer64Anon:
705  return "Pointer64Anon";
706  case Page21:
707  return "Page21";
708  case PageOffset12:
709  return "PageOffset12";
710  case GOTPage21:
711  return "GOTPage21";
712  case GOTPageOffset12:
713  return "GOTPageOffset12";
714  case PointerToGOT:
715  return "PointerToGOT";
716  case PairedAddend:
717  return "PairedAddend";
718  case LDRLiteral19:
719  return "LDRLiteral19";
720  case Delta32:
721  return "Delta32";
722  case Delta64:
723  return "Delta64";
724  case NegDelta32:
725  return "NegDelta32";
726  case NegDelta64:
727  return "NegDelta64";
728  default:
729  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
730  }
731 }
732 
733 } // end namespace jitlink
734 } // end namespace llvm
llvm::MachO::ARM64_RELOC_UNSIGNED
@ ARM64_RELOC_UNSIGNED
Definition: MachO.h:449
llvm::sys::Memory::MF_READ
@ MF_READ
Definition: Memory.h:55
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::MachO::relocation_info::r_length
uint32_t r_length
Definition: MachO.h:959
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:122
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:180
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")
llvm::sys::Memory::ProtectionFlags
ProtectionFlags
Definition: Memory.h:54
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::X86II::ImmShift
@ ImmShift
Definition: X86BaseInfo.h:834
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
llvm::sys::Memory::MF_EXEC
@ MF_EXEC
Definition: Memory.h:57
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
llvm::MachO::relocation_info
Definition: MachO.h:957
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:1605
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:246
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
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:136
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::JITTargetAddress
uint64_t JITTargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:42
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::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:75
llvm::MachO::relocation_info::r_symbolnum
uint32_t r_symbolnum
Definition: MachO.h:959