xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
13 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
14 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
16 #include "llvm/ExecutionEngine/Orc/Shared/MachOObjectFormat.h"
17 
18 #include "CompactUnwindSupport.h"
19 #include "DefineExternalSectionStartAndEndSymbols.h"
20 #include "MachOLinkGraphBuilder.h"
21 
22 #define DEBUG_TYPE "jitlink"
23 
24 using namespace llvm;
25 using namespace llvm::jitlink;
26 
27 namespace {
28 
29 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
30 public:
MachOLinkGraphBuilder_arm64(const object::MachOObjectFile & Obj,std::shared_ptr<orc::SymbolStringPool> SSP,SubtargetFeatures Features)31   MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj,
32                               std::shared_ptr<orc::SymbolStringPool> SSP,
33                               SubtargetFeatures Features)
34       : MachOLinkGraphBuilder(Obj, std::move(SSP), getObjectTriple(Obj),
35                               std::move(Features), aarch64::getEdgeKindName),
36         NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
37 
38 private:
39   enum MachOARM64RelocationKind : Edge::Kind {
40     MachOBranch26 = Edge::FirstRelocation,
41     MachOPointer32,
42     MachOPointer64,
43     MachOPointer64Anon,
44     MachOPointer64Authenticated,
45     MachOPage21,
46     MachOPageOffset12,
47     MachOGOTPage21,
48     MachOGOTPageOffset12,
49     MachOTLVPage21,
50     MachOTLVPageOffset12,
51     MachOPointerToGOT,
52     MachOPairedAddend,
53     MachOLDRLiteral19,
54     MachODelta32,
55     MachODelta64,
56     MachONegDelta32,
57     MachONegDelta64,
58   };
59 
getObjectTriple(const object::MachOObjectFile & Obj)60   static Triple getObjectTriple(const object::MachOObjectFile &Obj) {
61     // Get the CPU sub-type from the header.
62     // jitLink_MachO should already have validated that the buffer is big enough
63     // to cover a mach_header64 so this is safe.
64     uint32_t CPUSubType =
65         *(const support::ulittle32_t *)(Obj.getData().data() + 8);
66     CPUSubType &= ~MachO::CPU_SUBTYPE_MASK;
67     if (CPUSubType == MachO::CPU_SUBTYPE_ARM64E)
68       return Triple("arm64e-apple-darwin");
69     return Triple("arm64-apple-darwin");
70   }
71 
72   static Expected<MachOARM64RelocationKind>
getRelocationKind(const MachO::relocation_info & RI)73   getRelocationKind(const MachO::relocation_info &RI) {
74     switch (RI.r_type) {
75     case MachO::ARM64_RELOC_UNSIGNED:
76       if (!RI.r_pcrel) {
77         if (RI.r_length == 3)
78           return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
79         else if (RI.r_length == 2)
80           return MachOPointer32;
81       }
82       break;
83     case MachO::ARM64_RELOC_SUBTRACTOR:
84       // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
85       // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
86       // They may be turned into NegDelta<W> by parsePairRelocation.
87       if (!RI.r_pcrel && RI.r_extern) {
88         if (RI.r_length == 2)
89           return MachODelta32;
90         else if (RI.r_length == 3)
91           return MachODelta64;
92       }
93       break;
94     case MachO::ARM64_RELOC_BRANCH26:
95       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
96         return MachOBranch26;
97       break;
98     case MachO::ARM64_RELOC_PAGE21:
99       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
100         return MachOPage21;
101       break;
102     case MachO::ARM64_RELOC_PAGEOFF12:
103       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
104         return MachOPageOffset12;
105       break;
106     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
107       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
108         return MachOGOTPage21;
109       break;
110     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
111       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
112         return MachOGOTPageOffset12;
113       break;
114     case MachO::ARM64_RELOC_POINTER_TO_GOT:
115       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
116         return MachOPointerToGOT;
117       break;
118     case MachO::ARM64_RELOC_ADDEND:
119       if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
120         return MachOPairedAddend;
121       break;
122     case MachO::ARM64_RELOC_AUTHENTICATED_POINTER:
123       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 3)
124         return MachOPointer64Authenticated;
125       break;
126     case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
127       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
128         return MachOTLVPage21;
129       break;
130     case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
131       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
132         return MachOTLVPageOffset12;
133       break;
134     }
135 
136     return make_error<JITLinkError>(
137         "Unsupported arm64 relocation: address=" +
138         formatv("{0:x8}", RI.r_address) +
139         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
140         ", kind=" + formatv("{0:x1}", RI.r_type) +
141         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
142         ", extern=" + (RI.r_extern ? "true" : "false") +
143         ", length=" + formatv("{0:d}", RI.r_length));
144   }
145 
146   using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
147 
148   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
149   // returns the edge kind and addend to be used.
150   Expected<PairRelocInfo>
parsePairRelocation(Block & BlockToFix,Edge::Kind SubtractorKind,const MachO::relocation_info & SubRI,orc::ExecutorAddr FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)151   parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
152                       const MachO::relocation_info &SubRI,
153                       orc::ExecutorAddr FixupAddress, const char *FixupContent,
154                       object::relocation_iterator &UnsignedRelItr,
155                       object::relocation_iterator &RelEnd) {
156     using namespace support;
157 
158     assert(((SubtractorKind == MachODelta32 && SubRI.r_length == 2) ||
159             (SubtractorKind == MachODelta64 && SubRI.r_length == 3)) &&
160            "Subtractor kind should match length");
161     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
162     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
163 
164     if (UnsignedRelItr == RelEnd)
165       return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
166                                       "UNSIGNED relocation");
167 
168     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
169 
170     if (SubRI.r_address != UnsignedRI.r_address)
171       return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
172                                       "point to different addresses");
173 
174     if (SubRI.r_length != UnsignedRI.r_length)
175       return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
176                                       "UNSIGNED reloc must match");
177 
178     Symbol *FromSymbol;
179     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
180       FromSymbol = FromSymbolOrErr->GraphSymbol;
181     else
182       return FromSymbolOrErr.takeError();
183 
184     // Read the current fixup value.
185     uint64_t FixupValue = 0;
186     if (SubRI.r_length == 3)
187       FixupValue = *(const little64_t *)FixupContent;
188     else
189       FixupValue = *(const little32_t *)FixupContent;
190 
191     // Find 'ToSymbol' using symbol number or address, depending on whether the
192     // paired UNSIGNED relocation is extern.
193     Symbol *ToSymbol = nullptr;
194     if (UnsignedRI.r_extern) {
195       // Find target symbol by symbol index.
196       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
197         ToSymbol = ToSymbolOrErr->GraphSymbol;
198       else
199         return ToSymbolOrErr.takeError();
200     } else {
201       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
202       if (!ToSymbolSec)
203         return ToSymbolSec.takeError();
204       ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
205       assert(ToSymbol && "No symbol for section");
206       FixupValue -= ToSymbol->getAddress().getValue();
207     }
208 
209     Edge::Kind DeltaKind;
210     Symbol *TargetSymbol;
211     uint64_t Addend;
212 
213     bool FixingFromSymbol = true;
214     if (&BlockToFix == &FromSymbol->getAddressable()) {
215       if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
216         // From and To are symbols in the same block. Decide direction by offset
217         // instead.
218         if (ToSymbol->getAddress() > FixupAddress)
219           FixingFromSymbol = true;
220         else if (FromSymbol->getAddress() > FixupAddress)
221           FixingFromSymbol = false;
222         else
223           FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
224       } else
225         FixingFromSymbol = true;
226     } else {
227       if (&BlockToFix == &ToSymbol->getAddressable())
228         FixingFromSymbol = false;
229       else {
230         // BlockToFix was neither FromSymbol nor ToSymbol.
231         return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
232                                         "either 'A' or 'B' (or a symbol in one "
233                                         "of their alt-entry groups)");
234       }
235     }
236 
237     if (FixingFromSymbol) {
238       TargetSymbol = ToSymbol;
239       DeltaKind = (SubRI.r_length == 3) ? aarch64::Delta64 : aarch64::Delta32;
240       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
241       // FIXME: handle extern 'from'.
242     } else {
243       TargetSymbol = &*FromSymbol;
244       DeltaKind =
245           (SubRI.r_length == 3) ? aarch64::NegDelta64 : aarch64::NegDelta32;
246       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
247     }
248 
249     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
250   }
251 
addRelocations()252   Error addRelocations() override {
253     using namespace support;
254     auto &Obj = getObject();
255 
256     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
257 
258     for (auto &S : Obj.sections()) {
259 
260       orc::ExecutorAddr SectionAddress(S.getAddress());
261 
262       // Skip relocations virtual sections.
263       if (S.isVirtual()) {
264         if (S.relocation_begin() != S.relocation_end())
265           return make_error<JITLinkError>("Virtual section contains "
266                                           "relocations");
267         continue;
268       }
269 
270       auto NSec =
271           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
272       if (!NSec)
273         return NSec.takeError();
274 
275       // Skip relocations for MachO sections without corresponding graph
276       // sections.
277       {
278         if (!NSec->GraphSection) {
279           LLVM_DEBUG({
280             dbgs() << "  Skipping relocations for MachO section "
281                    << NSec->SegName << "/" << NSec->SectName
282                    << " which has no associated graph section\n";
283           });
284           continue;
285         }
286       }
287 
288       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
289            RelItr != RelEnd; ++RelItr) {
290 
291         MachO::relocation_info RI = getRelocationInfo(RelItr);
292 
293         // Validate the relocation kind.
294         auto MachORelocKind = getRelocationKind(RI);
295         if (!MachORelocKind)
296           return MachORelocKind.takeError();
297 
298         // Find the address of the value to fix up.
299         orc::ExecutorAddr FixupAddress =
300             SectionAddress + (uint32_t)RI.r_address;
301         LLVM_DEBUG({
302           dbgs() << "  " << NSec->SectName << " + "
303                  << formatv("{0:x8}", RI.r_address) << ":\n";
304         });
305 
306         // Find the block that the fixup points to.
307         Block *BlockToFix = nullptr;
308         {
309           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
310           if (!SymbolToFixOrErr)
311             return SymbolToFixOrErr.takeError();
312           BlockToFix = &SymbolToFixOrErr->getBlock();
313         }
314 
315         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
316             BlockToFix->getAddress() + BlockToFix->getContent().size())
317           return make_error<JITLinkError>(
318               "Relocation content extends past end of fixup block");
319 
320         Edge::Kind Kind = Edge::Invalid;
321 
322         // Get a pointer to the fixup content.
323         const char *FixupContent = BlockToFix->getContent().data() +
324                                    (FixupAddress - BlockToFix->getAddress());
325 
326         // The target symbol and addend will be populated by the switch below.
327         Symbol *TargetSymbol = nullptr;
328         uint64_t Addend = 0;
329 
330         if (*MachORelocKind == MachOPairedAddend) {
331           // If this is an Addend relocation then process it and move to the
332           // paired reloc.
333 
334           Addend = SignExtend64(RI.r_symbolnum, 24);
335 
336           ++RelItr;
337           if (RelItr == RelEnd)
338             return make_error<JITLinkError>("Unpaired Addend reloc at " +
339                                             formatv("{0:x16}", FixupAddress));
340           RI = getRelocationInfo(RelItr);
341 
342           MachORelocKind = getRelocationKind(RI);
343           if (!MachORelocKind)
344             return MachORelocKind.takeError();
345 
346           if (*MachORelocKind != MachOBranch26 &&
347               *MachORelocKind != MachOPage21 &&
348               *MachORelocKind != MachOPageOffset12)
349             return make_error<JITLinkError>(
350                 "Invalid relocation pair: Addend + " +
351                 StringRef(getMachOARM64RelocationKindName(*MachORelocKind)));
352 
353           LLVM_DEBUG({
354             dbgs() << "    Addend: value = " << formatv("{0:x6}", Addend)
355                    << ", pair is "
356                    << getMachOARM64RelocationKindName(*MachORelocKind) << "\n";
357           });
358 
359           // Find the address of the value to fix up.
360           orc::ExecutorAddr PairedFixupAddress =
361               SectionAddress + (uint32_t)RI.r_address;
362           if (PairedFixupAddress != FixupAddress)
363             return make_error<JITLinkError>("Paired relocation points at "
364                                             "different target");
365         }
366 
367         switch (*MachORelocKind) {
368         case MachOBranch26: {
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 & 0x7fffffff) != 0x14000000)
375             return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
376                                             "instruction with a zero addend");
377           Kind = aarch64::Branch26PCRel;
378           break;
379         }
380         case MachOPointer32:
381           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
382             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
383           else
384             return TargetSymbolOrErr.takeError();
385           Addend = *(const ulittle32_t *)FixupContent;
386           Kind = aarch64::Pointer32;
387           break;
388         case MachOPointer64:
389         case MachOPointer64Authenticated:
390           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
391             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
392           else
393             return TargetSymbolOrErr.takeError();
394           Addend = *(const ulittle64_t *)FixupContent;
395           Kind = *MachORelocKind == MachOPointer64
396                      ? aarch64::Pointer64
397                      : aarch64::Pointer64Authenticated;
398           break;
399         case MachOPointer64Anon: {
400           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
401           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
402           if (!TargetNSec)
403             return TargetNSec.takeError();
404           if (auto TargetSymbolOrErr =
405                   findSymbolByAddress(*TargetNSec, TargetAddress))
406             TargetSymbol = &*TargetSymbolOrErr;
407           else
408             return TargetSymbolOrErr.takeError();
409           Addend = TargetAddress - TargetSymbol->getAddress();
410           Kind = aarch64::Pointer64;
411           break;
412         }
413         case MachOPage21:
414         case MachOGOTPage21:
415         case MachOTLVPage21: {
416           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
417             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
418           else
419             return TargetSymbolOrErr.takeError();
420           uint32_t Instr = *(const ulittle32_t *)FixupContent;
421           if ((Instr & 0xffffffe0) != 0x90000000)
422             return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
423                                             "ADRP instruction with a zero "
424                                             "addend");
425 
426           if (*MachORelocKind == MachOPage21) {
427             Kind = aarch64::Page21;
428           } else if (*MachORelocKind == MachOGOTPage21) {
429             Kind = aarch64::RequestGOTAndTransformToPage21;
430           } else if (*MachORelocKind == MachOTLVPage21) {
431             Kind = aarch64::RequestTLVPAndTransformToPage21;
432           }
433           break;
434         }
435         case MachOPageOffset12: {
436           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
437             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
438           else
439             return TargetSymbolOrErr.takeError();
440           uint32_t Instr = *(const ulittle32_t *)FixupContent;
441           uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
442           if (EncodedAddend != 0)
443             return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
444                                             "encoded addend");
445           Kind = aarch64::PageOffset12;
446           break;
447         }
448         case MachOGOTPageOffset12:
449         case MachOTLVPageOffset12: {
450           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
451             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
452           else
453             return TargetSymbolOrErr.takeError();
454           uint32_t Instr = *(const ulittle32_t *)FixupContent;
455           if ((Instr & 0xfffffc00) != 0xf9400000)
456             return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
457                                             "immediate instruction with a zero "
458                                             "addend");
459 
460           if (*MachORelocKind == MachOGOTPageOffset12) {
461             Kind = aarch64::RequestGOTAndTransformToPageOffset12;
462           } else if (*MachORelocKind == MachOTLVPageOffset12) {
463             Kind = aarch64::RequestTLVPAndTransformToPageOffset12;
464           }
465           break;
466         }
467         case MachOPointerToGOT:
468           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
469             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
470           else
471             return TargetSymbolOrErr.takeError();
472 
473           Kind = aarch64::RequestGOTAndTransformToDelta32;
474           break;
475         case MachODelta32:
476         case MachODelta64: {
477           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
478           // parsePairRelocation handles the paired reloc, and returns the
479           // edge kind to be used (either Delta32/Delta64, or
480           // NegDelta32/NegDelta64, depending on the direction of the
481           // subtraction) along with the addend.
482           auto PairInfo =
483               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
484                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
485           if (!PairInfo)
486             return PairInfo.takeError();
487           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
488           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
489           break;
490         }
491         default:
492           llvm_unreachable("Special relocation kind should not appear in "
493                            "mach-o file");
494         }
495 
496         LLVM_DEBUG({
497           dbgs() << "    ";
498           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
499                   Addend);
500           printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(Kind));
501           dbgs() << "\n";
502         });
503         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
504                             *TargetSymbol, Addend);
505       }
506     }
507     return Error::success();
508   }
509 
510   /// Return the string name of the given MachO arm64 edge kind.
getMachOARM64RelocationKindName(Edge::Kind R)511   const char *getMachOARM64RelocationKindName(Edge::Kind R) {
512     switch (R) {
513     case MachOBranch26:
514       return "MachOBranch26";
515     case MachOPointer64:
516       return "MachOPointer64";
517     case MachOPointer64Anon:
518       return "MachOPointer64Anon";
519     case MachOPointer64Authenticated:
520       return "MachOPointer64Authenticated";
521     case MachOPage21:
522       return "MachOPage21";
523     case MachOPageOffset12:
524       return "MachOPageOffset12";
525     case MachOGOTPage21:
526       return "MachOGOTPage21";
527     case MachOGOTPageOffset12:
528       return "MachOGOTPageOffset12";
529     case MachOTLVPage21:
530       return "MachOTLVPage21";
531     case MachOTLVPageOffset12:
532       return "MachOTLVPageOffset12";
533     case MachOPointerToGOT:
534       return "MachOPointerToGOT";
535     case MachOPairedAddend:
536       return "MachOPairedAddend";
537     case MachOLDRLiteral19:
538       return "MachOLDRLiteral19";
539     case MachODelta32:
540       return "MachODelta32";
541     case MachODelta64:
542       return "MachODelta64";
543     case MachONegDelta32:
544       return "MachONegDelta32";
545     case MachONegDelta64:
546       return "MachONegDelta64";
547     default:
548       return getGenericEdgeKindName(R);
549     }
550   }
551 
552   unsigned NumSymbols = 0;
553 };
554 
555 } // namespace
556 
557 namespace llvm {
558 namespace jitlink {
559 
buildTables_MachO_arm64(LinkGraph & G)560 Error buildTables_MachO_arm64(LinkGraph &G) {
561   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
562 
563   aarch64::GOTTableManager GOT(G);
564   aarch64::PLTTableManager PLT(G, GOT);
565   visitExistingEdges(G, GOT, PLT);
566   return Error::success();
567 }
568 
569 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
570   friend class JITLinker<MachOJITLinker_arm64>;
571 
572 public:
MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)573   MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
574                        std::unique_ptr<LinkGraph> G,
575                        PassConfiguration PassConfig)
576       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
577 
578 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const579   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
580     return aarch64::applyFixup(G, B, E, nullptr);
581   }
582 
583   uint64_t NullValue = 0;
584 };
585 
createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer,std::shared_ptr<orc::SymbolStringPool> SSP)586 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromMachOObject_arm64(
587     MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
588   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
589   if (!MachOObj)
590     return MachOObj.takeError();
591 
592   auto Features = (*MachOObj)->getFeatures();
593   if (!Features)
594     return Features.takeError();
595 
596   return MachOLinkGraphBuilder_arm64(**MachOObj, std::move(SSP),
597                                      std::move(*Features))
598       .buildGraph();
599 }
600 
applyPACSigningToModInitPointers(LinkGraph & G)601 static Error applyPACSigningToModInitPointers(LinkGraph &G) {
602   assert(G.getTargetTriple().getSubArch() == Triple::AArch64SubArch_arm64e &&
603          "PAC signing only valid for arm64e");
604 
605   if (auto *ModInitSec = G.findSectionByName("__DATA,__mod_init_func")) {
606     for (auto *B : ModInitSec->blocks()) {
607       for (auto &E : B->edges()) {
608         if (E.getKind() == aarch64::Pointer64) {
609 
610           // Check that we have room to encode pointer signing bits.
611           if (E.getAddend() >> 32)
612             return make_error<JITLinkError>(
613                 "In " + G.getName() + ", __mod_init_func pointer at " +
614                 formatv("{0:x}", B->getFixupAddress(E).getValue()) +
615                 " has data in high bits of addend (addend >= 2^32)");
616 
617           // Change edge to Pointer64Authenticated, encode signing:
618           // key = asia, discriminator = 0, diversity = 0.
619           Edge::AddendT SigningBits = 0x1ULL << 63;
620           E.setKind(aarch64::Pointer64Authenticated);
621           E.setAddend(E.getAddend() | SigningBits);
622         }
623       }
624     }
625   }
626 
627   return Error::success();
628 }
629 
630 struct CompactUnwindTraits_MachO_arm64
631     : public CompactUnwindTraits<CompactUnwindTraits_MachO_arm64,
632                                  /* PointerSize = */ 8> {
633   // FIXME: Reinstate once we no longer need the MSVC workaround. See
634   //        FIXME for CompactUnwindTraits in CompactUnwindSupport.h.
635   // constexpr static size_t PointerSize = 8;
636 
637   constexpr static endianness Endianness = endianness::little;
638 
639   constexpr static uint32_t EncodingModeMask = 0x0f000000;
640   constexpr static uint32_t DWARFSectionOffsetMask = 0x00ffffff;
641 
642   using GOTManager = aarch64::GOTTableManager;
643 
encodingSpecifiesDWARFllvm::jitlink::CompactUnwindTraits_MachO_arm64644   static bool encodingSpecifiesDWARF(uint32_t Encoding) {
645     constexpr uint32_t DWARFMode = 0x03000000;
646     return (Encoding & EncodingModeMask) == DWARFMode;
647   }
648 
encodingCannotBeMergedllvm::jitlink::CompactUnwindTraits_MachO_arm64649   static bool encodingCannotBeMerged(uint32_t Encoding) { return false; }
650 };
651 
link_MachO_arm64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)652 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
653                       std::unique_ptr<JITLinkContext> Ctx) {
654 
655   PassConfiguration Config;
656 
657   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
658     // Add a mark-live pass.
659     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
660       Config.PrePrunePasses.push_back(std::move(MarkLive));
661     else
662       Config.PrePrunePasses.push_back(markAllSymbolsLive);
663 
664     // Add eh-frame passes.
665     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64());
666     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64());
667 
668     // Create a compact-unwind manager for use in passes below.
669     auto CompactUnwindMgr =
670         std::make_shared<CompactUnwindManager<CompactUnwindTraits_MachO_arm64>>(
671             orc::MachOCompactUnwindSectionName, orc::MachOUnwindInfoSectionName,
672             orc::MachOEHFrameSectionName);
673 
674     // Add compact unwind prepare pass.
675     Config.PrePrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) {
676       return CompactUnwindMgr->prepareForPrune(G);
677     });
678 
679     // Resolve any external section start / end symbols.
680     Config.PostAllocationPasses.push_back(
681         createDefineExternalSectionStartAndEndSymbolsPass(
682             identifyMachOSectionStartAndEndSymbols));
683 
684     // Add an in-place GOT/Stubs pass.
685     Config.PostPrunePasses.push_back(buildTables_MachO_arm64);
686 
687     // If this is an arm64e graph then add pointer signing passes.
688     if (G->getTargetTriple().isArm64e()) {
689       Config.PostPrunePasses.push_back(applyPACSigningToModInitPointers);
690       Config.PostPrunePasses.push_back(
691           aarch64::createEmptyPointerSigningFunction);
692       Config.PreFixupPasses.push_back(
693           aarch64::lowerPointer64AuthEdgesToSigningFunction);
694     }
695 
696     // Reserve unwind-info space.
697     Config.PostPrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) {
698       return CompactUnwindMgr->processAndReserveUnwindInfo(G);
699     });
700 
701     // Translate compact-unwind to unwind-info.
702     Config.PreFixupPasses.push_back([CompactUnwindMgr](LinkGraph &G) {
703       return CompactUnwindMgr->writeUnwindInfo(G);
704     });
705   }
706 
707   if (auto Err = Ctx->modifyPassConfig(*G, Config))
708     return Ctx->notifyFailed(std::move(Err));
709 
710   // Construct a JITLinker and run the link function.
711   MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
712 }
713 
createEHFrameSplitterPass_MachO_arm64()714 LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64() {
715   return DWARFRecordSectionSplitter(orc::MachOEHFrameSectionName);
716 }
717 
createEHFrameEdgeFixerPass_MachO_arm64()718 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64() {
719   return EHFrameEdgeFixer(orc::MachOEHFrameSectionName, aarch64::PointerSize,
720                           aarch64::Pointer32, aarch64::Pointer64,
721                           aarch64::Delta32, aarch64::Delta64,
722                           aarch64::NegDelta32);
723 }
724 
725 } // end namespace jitlink
726 } // end namespace llvm
727