xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // MachO/x86-64 jit-link implementation.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
1481ad6265SDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h"
160b57cec5SDimitry Andric 
17*0fca6ea1SDimitry Andric #include "DefineExternalSectionStartAndEndSymbols.h"
188bcb0991SDimitry Andric #include "MachOLinkGraphBuilder.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric using namespace llvm::jitlink;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace {
260b57cec5SDimitry Andric 
278bcb0991SDimitry Andric class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
280b57cec5SDimitry Andric public:
MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile & Obj,SubtargetFeatures Features)2906c3fb27SDimitry Andric   MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj,
3006c3fb27SDimitry Andric                                SubtargetFeatures Features)
31fe6060f1SDimitry Andric       : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"),
3206c3fb27SDimitry Andric                               std::move(Features), x86_64::getEdgeKindName) {}
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric private:
35fe6060f1SDimitry Andric   enum MachONormalizedRelocationType : unsigned {
36fe6060f1SDimitry Andric     MachOBranch32,
37fe6060f1SDimitry Andric     MachOPointer32,
38fe6060f1SDimitry Andric     MachOPointer64,
39fe6060f1SDimitry Andric     MachOPointer64Anon,
40fe6060f1SDimitry Andric     MachOPCRel32,
41fe6060f1SDimitry Andric     MachOPCRel32Minus1,
42fe6060f1SDimitry Andric     MachOPCRel32Minus2,
43fe6060f1SDimitry Andric     MachOPCRel32Minus4,
44fe6060f1SDimitry Andric     MachOPCRel32Anon,
45fe6060f1SDimitry Andric     MachOPCRel32Minus1Anon,
46fe6060f1SDimitry Andric     MachOPCRel32Minus2Anon,
47fe6060f1SDimitry Andric     MachOPCRel32Minus4Anon,
48fe6060f1SDimitry Andric     MachOPCRel32GOTLoad,
49fe6060f1SDimitry Andric     MachOPCRel32GOT,
50fe6060f1SDimitry Andric     MachOPCRel32TLV,
51fe6060f1SDimitry Andric     MachOSubtractor32,
52fe6060f1SDimitry Andric     MachOSubtractor64,
53fe6060f1SDimitry Andric   };
54fe6060f1SDimitry Andric 
55fe6060f1SDimitry Andric   static Expected<MachONormalizedRelocationType>
getRelocKind(const MachO::relocation_info & RI)56fe6060f1SDimitry Andric   getRelocKind(const MachO::relocation_info &RI) {
570b57cec5SDimitry Andric     switch (RI.r_type) {
580b57cec5SDimitry Andric     case MachO::X86_64_RELOC_UNSIGNED:
598bcb0991SDimitry Andric       if (!RI.r_pcrel) {
608bcb0991SDimitry Andric         if (RI.r_length == 3)
61fe6060f1SDimitry Andric           return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
628bcb0991SDimitry Andric         else if (RI.r_extern && RI.r_length == 2)
63fe6060f1SDimitry Andric           return MachOPointer32;
648bcb0991SDimitry Andric       }
650b57cec5SDimitry Andric       break;
660b57cec5SDimitry Andric     case MachO::X86_64_RELOC_SIGNED:
670b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_length == 2)
68fe6060f1SDimitry Andric         return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon;
690b57cec5SDimitry Andric       break;
700b57cec5SDimitry Andric     case MachO::X86_64_RELOC_BRANCH:
710b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
72fe6060f1SDimitry Andric         return MachOBranch32;
730b57cec5SDimitry Andric       break;
740b57cec5SDimitry Andric     case MachO::X86_64_RELOC_GOT_LOAD:
750b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
76fe6060f1SDimitry Andric         return MachOPCRel32GOTLoad;
770b57cec5SDimitry Andric       break;
780b57cec5SDimitry Andric     case MachO::X86_64_RELOC_GOT:
790b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
80fe6060f1SDimitry Andric         return MachOPCRel32GOT;
810b57cec5SDimitry Andric       break;
820b57cec5SDimitry Andric     case MachO::X86_64_RELOC_SUBTRACTOR:
830b57cec5SDimitry Andric       if (!RI.r_pcrel && RI.r_extern) {
840b57cec5SDimitry Andric         if (RI.r_length == 2)
85fe6060f1SDimitry Andric           return MachOSubtractor32;
860b57cec5SDimitry Andric         else if (RI.r_length == 3)
87fe6060f1SDimitry Andric           return MachOSubtractor64;
880b57cec5SDimitry Andric       }
890b57cec5SDimitry Andric       break;
900b57cec5SDimitry Andric     case MachO::X86_64_RELOC_SIGNED_1:
910b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_length == 2)
92fe6060f1SDimitry Andric         return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon;
930b57cec5SDimitry Andric       break;
940b57cec5SDimitry Andric     case MachO::X86_64_RELOC_SIGNED_2:
950b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_length == 2)
96fe6060f1SDimitry Andric         return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon;
970b57cec5SDimitry Andric       break;
980b57cec5SDimitry Andric     case MachO::X86_64_RELOC_SIGNED_4:
990b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_length == 2)
100fe6060f1SDimitry Andric         return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon;
1010b57cec5SDimitry Andric       break;
1020b57cec5SDimitry Andric     case MachO::X86_64_RELOC_TLV:
1030b57cec5SDimitry Andric       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
104fe6060f1SDimitry Andric         return MachOPCRel32TLV;
1050b57cec5SDimitry Andric       break;
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric     return make_error<JITLinkError>(
1090b57cec5SDimitry Andric         "Unsupported x86-64 relocation: address=" +
1100b57cec5SDimitry Andric         formatv("{0:x8}", RI.r_address) +
1110b57cec5SDimitry Andric         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
1120b57cec5SDimitry Andric         ", kind=" + formatv("{0:x1}", RI.r_type) +
1130b57cec5SDimitry Andric         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
1140b57cec5SDimitry Andric         ", extern=" + (RI.r_extern ? "true" : "false") +
1150b57cec5SDimitry Andric         ", length=" + formatv("{0:d}", RI.r_length));
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
118fe6060f1SDimitry Andric   using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
1210b57cec5SDimitry Andric   // returns the edge kind and addend to be used.
parsePairRelocation(Block & BlockToFix,MachONormalizedRelocationType SubtractorKind,const MachO::relocation_info & SubRI,orc::ExecutorAddr FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)122fe6060f1SDimitry Andric   Expected<PairRelocInfo> parsePairRelocation(
123fe6060f1SDimitry Andric       Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
12404eeddc0SDimitry Andric       const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress,
125fe6060f1SDimitry Andric       const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
1260b57cec5SDimitry Andric       object::relocation_iterator &RelEnd) {
1270b57cec5SDimitry Andric     using namespace support;
1280b57cec5SDimitry Andric 
129fe6060f1SDimitry Andric     assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) ||
130fe6060f1SDimitry Andric             (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) &&
1310b57cec5SDimitry Andric            "Subtractor kind should match length");
1320b57cec5SDimitry Andric     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
1330b57cec5SDimitry Andric     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     if (UnsignedRelItr == RelEnd)
1360b57cec5SDimitry Andric       return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
1370b57cec5SDimitry Andric                                       "UNSIGNED relocation");
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric     if (SubRI.r_address != UnsignedRI.r_address)
1420b57cec5SDimitry Andric       return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
1430b57cec5SDimitry Andric                                       "point to different addresses");
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric     if (SubRI.r_length != UnsignedRI.r_length)
1460b57cec5SDimitry Andric       return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
1470b57cec5SDimitry Andric                                       "UNSIGNED reloc must match");
1480b57cec5SDimitry Andric 
1498bcb0991SDimitry Andric     Symbol *FromSymbol;
1508bcb0991SDimitry Andric     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
1518bcb0991SDimitry Andric       FromSymbol = FromSymbolOrErr->GraphSymbol;
1528bcb0991SDimitry Andric     else
1538bcb0991SDimitry Andric       return FromSymbolOrErr.takeError();
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric     // Read the current fixup value.
1560b57cec5SDimitry Andric     uint64_t FixupValue = 0;
1570b57cec5SDimitry Andric     if (SubRI.r_length == 3)
1580b57cec5SDimitry Andric       FixupValue = *(const little64_t *)FixupContent;
1590b57cec5SDimitry Andric     else
1600b57cec5SDimitry Andric       FixupValue = *(const little32_t *)FixupContent;
1610b57cec5SDimitry Andric 
1628bcb0991SDimitry Andric     // Find 'ToSymbol' using symbol number or address, depending on whether the
1630b57cec5SDimitry Andric     // paired UNSIGNED relocation is extern.
1648bcb0991SDimitry Andric     Symbol *ToSymbol = nullptr;
1650b57cec5SDimitry Andric     if (UnsignedRI.r_extern) {
1668bcb0991SDimitry Andric       // Find target symbol by symbol index.
1678bcb0991SDimitry Andric       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
1688bcb0991SDimitry Andric         ToSymbol = ToSymbolOrErr->GraphSymbol;
1690b57cec5SDimitry Andric       else
1708bcb0991SDimitry Andric         return ToSymbolOrErr.takeError();
1710b57cec5SDimitry Andric     } else {
172e8d8bef9SDimitry Andric       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
173e8d8bef9SDimitry Andric       if (!ToSymbolSec)
174e8d8bef9SDimitry Andric         return ToSymbolSec.takeError();
175349cc55cSDimitry Andric       ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
176e8d8bef9SDimitry Andric       assert(ToSymbol && "No symbol for section");
17704eeddc0SDimitry Andric       FixupValue -= ToSymbol->getAddress().getValue();
1780b57cec5SDimitry Andric     }
1790b57cec5SDimitry Andric 
180fe6060f1SDimitry Andric     Edge::Kind DeltaKind;
1818bcb0991SDimitry Andric     Symbol *TargetSymbol;
1820b57cec5SDimitry Andric     uint64_t Addend;
183cb14a3feSDimitry Andric 
184cb14a3feSDimitry Andric     bool FixingFromSymbol = true;
1858bcb0991SDimitry Andric     if (&BlockToFix == &FromSymbol->getAddressable()) {
186cb14a3feSDimitry Andric       if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
187cb14a3feSDimitry Andric         // From and To are symbols in the same block. Decide direction by offset
188cb14a3feSDimitry Andric         // instead.
189cb14a3feSDimitry Andric         if (ToSymbol->getAddress() > FixupAddress)
190cb14a3feSDimitry Andric           FixingFromSymbol = true;
191cb14a3feSDimitry Andric         else if (FromSymbol->getAddress() > FixupAddress)
192cb14a3feSDimitry Andric           FixingFromSymbol = false;
193cb14a3feSDimitry Andric         else
194cb14a3feSDimitry Andric           FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
195cb14a3feSDimitry Andric       } else
196cb14a3feSDimitry Andric         FixingFromSymbol = true;
197cb14a3feSDimitry Andric     } else {
198cb14a3feSDimitry Andric       if (&BlockToFix == &ToSymbol->getAddressable())
199cb14a3feSDimitry Andric         FixingFromSymbol = false;
200cb14a3feSDimitry Andric       else {
201cb14a3feSDimitry Andric         // BlockToFix was neither FromSymbol nor ToSymbol.
202cb14a3feSDimitry Andric         return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
203cb14a3feSDimitry Andric                                         "either 'A' or 'B' (or a symbol in one "
204cb14a3feSDimitry Andric                                         "of their alt-entry groups)");
205cb14a3feSDimitry Andric       }
206cb14a3feSDimitry Andric     }
207cb14a3feSDimitry Andric 
208cb14a3feSDimitry Andric     if (FixingFromSymbol) {
2098bcb0991SDimitry Andric       TargetSymbol = ToSymbol;
210fe6060f1SDimitry Andric       DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
2118bcb0991SDimitry Andric       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
2120b57cec5SDimitry Andric       // FIXME: handle extern 'from'.
213cb14a3feSDimitry Andric     } else {
2148bcb0991SDimitry Andric       TargetSymbol = FromSymbol;
215fe6060f1SDimitry Andric       DeltaKind =
216fe6060f1SDimitry Andric           (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
2178bcb0991SDimitry Andric       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric 
2208bcb0991SDimitry Andric     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
2210b57cec5SDimitry Andric   }
2220b57cec5SDimitry Andric 
addRelocations()2230b57cec5SDimitry Andric   Error addRelocations() override {
2240b57cec5SDimitry Andric     using namespace support;
2250b57cec5SDimitry Andric     auto &Obj = getObject();
2260b57cec5SDimitry Andric 
227e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
228e8d8bef9SDimitry Andric 
229bdd1243dSDimitry Andric     for (const auto &S : Obj.sections()) {
2300b57cec5SDimitry Andric 
23104eeddc0SDimitry Andric       orc::ExecutorAddr SectionAddress(S.getAddress());
2320b57cec5SDimitry Andric 
2335ffd83dbSDimitry Andric       // Skip relocations virtual sections.
2348bcb0991SDimitry Andric       if (S.isVirtual()) {
2358bcb0991SDimitry Andric         if (S.relocation_begin() != S.relocation_end())
2368bcb0991SDimitry Andric           return make_error<JITLinkError>("Virtual section contains "
2378bcb0991SDimitry Andric                                           "relocations");
2388bcb0991SDimitry Andric         continue;
2398bcb0991SDimitry Andric       }
2408bcb0991SDimitry Andric 
241349cc55cSDimitry Andric       auto NSec =
242349cc55cSDimitry Andric           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
243349cc55cSDimitry Andric       if (!NSec)
244349cc55cSDimitry Andric         return NSec.takeError();
245349cc55cSDimitry Andric 
246349cc55cSDimitry Andric       // Skip relocations for MachO sections without corresponding graph
247349cc55cSDimitry Andric       // sections.
2485ffd83dbSDimitry Andric       {
249349cc55cSDimitry Andric         if (!NSec->GraphSection) {
2505ffd83dbSDimitry Andric           LLVM_DEBUG({
251e8d8bef9SDimitry Andric             dbgs() << "  Skipping relocations for MachO section "
252349cc55cSDimitry Andric                    << NSec->SegName << "/" << NSec->SectName
2535ffd83dbSDimitry Andric                    << " which has no associated graph section\n";
2545ffd83dbSDimitry Andric           });
2555ffd83dbSDimitry Andric           continue;
2565ffd83dbSDimitry Andric         }
2575ffd83dbSDimitry Andric       }
2585ffd83dbSDimitry Andric 
2595ffd83dbSDimitry Andric       // Add relocations for section.
2600b57cec5SDimitry Andric       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
2610b57cec5SDimitry Andric            RelItr != RelEnd; ++RelItr) {
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric         MachO::relocation_info RI = getRelocationInfo(RelItr);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric         // Find the address of the value to fix up.
26604eeddc0SDimitry Andric         auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric         LLVM_DEBUG({
269349cc55cSDimitry Andric           dbgs() << "  " << NSec->SectName << " + "
270e8d8bef9SDimitry Andric                  << formatv("{0:x8}", RI.r_address) << ":\n";
2710b57cec5SDimitry Andric         });
2720b57cec5SDimitry Andric 
2738bcb0991SDimitry Andric         // Find the block that the fixup points to.
2748bcb0991SDimitry Andric         Block *BlockToFix = nullptr;
2750b57cec5SDimitry Andric         {
276349cc55cSDimitry Andric           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
2778bcb0991SDimitry Andric           if (!SymbolToFixOrErr)
2788bcb0991SDimitry Andric             return SymbolToFixOrErr.takeError();
2798bcb0991SDimitry Andric           BlockToFix = &SymbolToFixOrErr->getBlock();
2800b57cec5SDimitry Andric         }
2810b57cec5SDimitry Andric 
28204eeddc0SDimitry Andric         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
2838bcb0991SDimitry Andric             BlockToFix->getAddress() + BlockToFix->getContent().size())
2840b57cec5SDimitry Andric           return make_error<JITLinkError>(
2858bcb0991SDimitry Andric               "Relocation extends past end of fixup block");
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric         // Get a pointer to the fixup content.
2888bcb0991SDimitry Andric         const char *FixupContent = BlockToFix->getContent().data() +
2898bcb0991SDimitry Andric                                    (FixupAddress - BlockToFix->getAddress());
2900b57cec5SDimitry Andric 
291fe6060f1SDimitry Andric         size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
292fe6060f1SDimitry Andric 
2938bcb0991SDimitry Andric         // The target symbol and addend will be populated by the switch below.
2948bcb0991SDimitry Andric         Symbol *TargetSymbol = nullptr;
2950b57cec5SDimitry Andric         uint64_t Addend = 0;
2960b57cec5SDimitry Andric 
297349cc55cSDimitry Andric         // Validate the relocation kind.
298fe6060f1SDimitry Andric         auto MachORelocKind = getRelocKind(RI);
299fe6060f1SDimitry Andric         if (!MachORelocKind)
300fe6060f1SDimitry Andric           return MachORelocKind.takeError();
301fe6060f1SDimitry Andric 
302fe6060f1SDimitry Andric         Edge::Kind Kind = Edge::Invalid;
303fe6060f1SDimitry Andric 
304fe6060f1SDimitry Andric         switch (*MachORelocKind) {
305fe6060f1SDimitry Andric         case MachOBranch32:
3068bcb0991SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3078bcb0991SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3080b57cec5SDimitry Andric           else
3098bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
310480093f4SDimitry Andric           Addend = *(const little32_t *)FixupContent;
311fe6060f1SDimitry Andric           Kind = x86_64::BranchPCRel32;
3128bcb0991SDimitry Andric           break;
313fe6060f1SDimitry Andric         case MachOPCRel32:
314fe6060f1SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
315fe6060f1SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
316fe6060f1SDimitry Andric           else
317fe6060f1SDimitry Andric             return TargetSymbolOrErr.takeError();
318fe6060f1SDimitry Andric           Addend = *(const little32_t *)FixupContent - 4;
319fe6060f1SDimitry Andric           Kind = x86_64::Delta32;
320fe6060f1SDimitry Andric           break;
321fe6060f1SDimitry Andric         case MachOPCRel32GOTLoad:
322fe6060f1SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
323fe6060f1SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
324fe6060f1SDimitry Andric           else
325fe6060f1SDimitry Andric             return TargetSymbolOrErr.takeError();
326fe6060f1SDimitry Andric           Addend = *(const little32_t *)FixupContent;
327349cc55cSDimitry Andric           Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
328fe6060f1SDimitry Andric           if (FixupOffset < 3)
329fe6060f1SDimitry Andric             return make_error<JITLinkError>("GOTLD at invalid offset " +
330fe6060f1SDimitry Andric                                             formatv("{0}", FixupOffset));
331fe6060f1SDimitry Andric           break;
332fe6060f1SDimitry Andric         case MachOPCRel32GOT:
333fe6060f1SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
334fe6060f1SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
335fe6060f1SDimitry Andric           else
336fe6060f1SDimitry Andric             return TargetSymbolOrErr.takeError();
337fe6060f1SDimitry Andric           Addend = *(const little32_t *)FixupContent - 4;
338fe6060f1SDimitry Andric           Kind = x86_64::RequestGOTAndTransformToDelta32;
339fe6060f1SDimitry Andric           break;
340fe6060f1SDimitry Andric         case MachOPCRel32TLV:
341fe6060f1SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
342fe6060f1SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
343fe6060f1SDimitry Andric           else
344fe6060f1SDimitry Andric             return TargetSymbolOrErr.takeError();
345fe6060f1SDimitry Andric           Addend = *(const little32_t *)FixupContent;
346349cc55cSDimitry Andric           Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
347349cc55cSDimitry Andric           if (FixupOffset < 3)
348349cc55cSDimitry Andric             return make_error<JITLinkError>("TLV at invalid offset " +
349349cc55cSDimitry Andric                                             formatv("{0}", FixupOffset));
350fe6060f1SDimitry Andric           break;
351fe6060f1SDimitry Andric         case MachOPointer32:
3528bcb0991SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3538bcb0991SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3548bcb0991SDimitry Andric           else
3558bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
3560b57cec5SDimitry Andric           Addend = *(const ulittle32_t *)FixupContent;
357fe6060f1SDimitry Andric           Kind = x86_64::Pointer32;
3580b57cec5SDimitry Andric           break;
359fe6060f1SDimitry Andric         case MachOPointer64:
3608bcb0991SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3618bcb0991SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3620b57cec5SDimitry Andric           else
3638bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
3640b57cec5SDimitry Andric           Addend = *(const ulittle64_t *)FixupContent;
365fe6060f1SDimitry Andric           Kind = x86_64::Pointer64;
3660b57cec5SDimitry Andric           break;
367fe6060f1SDimitry Andric         case MachOPointer64Anon: {
36804eeddc0SDimitry Andric           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
369349cc55cSDimitry Andric           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
370349cc55cSDimitry Andric           if (!TargetNSec)
371349cc55cSDimitry Andric             return TargetNSec.takeError();
372349cc55cSDimitry Andric           if (auto TargetSymbolOrErr =
373349cc55cSDimitry Andric                   findSymbolByAddress(*TargetNSec, TargetAddress))
3748bcb0991SDimitry Andric             TargetSymbol = &*TargetSymbolOrErr;
3750b57cec5SDimitry Andric           else
3768bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
3778bcb0991SDimitry Andric           Addend = TargetAddress - TargetSymbol->getAddress();
378fe6060f1SDimitry Andric           Kind = x86_64::Pointer64;
3790b57cec5SDimitry Andric           break;
3800b57cec5SDimitry Andric         }
381fe6060f1SDimitry Andric         case MachOPCRel32Minus1:
382fe6060f1SDimitry Andric         case MachOPCRel32Minus2:
383fe6060f1SDimitry Andric         case MachOPCRel32Minus4:
3848bcb0991SDimitry Andric           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3858bcb0991SDimitry Andric             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3860b57cec5SDimitry Andric           else
3878bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
388fe6060f1SDimitry Andric           Addend = *(const little32_t *)FixupContent - 4;
389fe6060f1SDimitry Andric           Kind = x86_64::Delta32;
3900b57cec5SDimitry Andric           break;
391fe6060f1SDimitry Andric         case MachOPCRel32Anon: {
39204eeddc0SDimitry Andric           orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
39304eeddc0SDimitry Andric                                           *(const little32_t *)FixupContent);
394349cc55cSDimitry Andric           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
395349cc55cSDimitry Andric           if (!TargetNSec)
396349cc55cSDimitry Andric             return TargetNSec.takeError();
397349cc55cSDimitry Andric           if (auto TargetSymbolOrErr =
398349cc55cSDimitry Andric                   findSymbolByAddress(*TargetNSec, TargetAddress))
3998bcb0991SDimitry Andric             TargetSymbol = &*TargetSymbolOrErr;
4000b57cec5SDimitry Andric           else
4018bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
402fe6060f1SDimitry Andric           Addend = TargetAddress - TargetSymbol->getAddress() - 4;
403fe6060f1SDimitry Andric           Kind = x86_64::Delta32;
4040b57cec5SDimitry Andric           break;
4050b57cec5SDimitry Andric         }
406fe6060f1SDimitry Andric         case MachOPCRel32Minus1Anon:
407fe6060f1SDimitry Andric         case MachOPCRel32Minus2Anon:
408fe6060f1SDimitry Andric         case MachOPCRel32Minus4Anon: {
40904eeddc0SDimitry Andric           orc::ExecutorAddrDiff Delta =
41004eeddc0SDimitry Andric               4 + orc::ExecutorAddrDiff(
411fe6060f1SDimitry Andric                       1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
41204eeddc0SDimitry Andric           orc::ExecutorAddr TargetAddress =
413fe6060f1SDimitry Andric               FixupAddress + Delta + *(const little32_t *)FixupContent;
414349cc55cSDimitry Andric           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
415349cc55cSDimitry Andric           if (!TargetNSec)
416349cc55cSDimitry Andric             return TargetNSec.takeError();
417349cc55cSDimitry Andric           if (auto TargetSymbolOrErr =
418349cc55cSDimitry Andric                   findSymbolByAddress(*TargetNSec, TargetAddress))
4198bcb0991SDimitry Andric             TargetSymbol = &*TargetSymbolOrErr;
4200b57cec5SDimitry Andric           else
4218bcb0991SDimitry Andric             return TargetSymbolOrErr.takeError();
422fe6060f1SDimitry Andric           Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
423fe6060f1SDimitry Andric           Kind = x86_64::Delta32;
4240b57cec5SDimitry Andric           break;
4250b57cec5SDimitry Andric         }
426fe6060f1SDimitry Andric         case MachOSubtractor32:
427fe6060f1SDimitry Andric         case MachOSubtractor64: {
4280b57cec5SDimitry Andric           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
4290b57cec5SDimitry Andric           // parsePairRelocation handles the paired reloc, and returns the
4300b57cec5SDimitry Andric           // edge kind to be used (either Delta32/Delta64, or
4310b57cec5SDimitry Andric           // NegDelta32/NegDelta64, depending on the direction of the
4320b57cec5SDimitry Andric           // subtraction) along with the addend.
4330b57cec5SDimitry Andric           auto PairInfo =
434fe6060f1SDimitry Andric               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
435fe6060f1SDimitry Andric                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
4360b57cec5SDimitry Andric           if (!PairInfo)
4370b57cec5SDimitry Andric             return PairInfo.takeError();
438fe6060f1SDimitry Andric           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
4398bcb0991SDimitry Andric           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
4400b57cec5SDimitry Andric           break;
4410b57cec5SDimitry Andric         }
4420b57cec5SDimitry Andric         }
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric         LLVM_DEBUG({
445e8d8bef9SDimitry Andric           dbgs() << "    ";
446fe6060f1SDimitry Andric           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
4470b57cec5SDimitry Andric                   Addend);
448fe6060f1SDimitry Andric           printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
4490b57cec5SDimitry Andric           dbgs() << "\n";
4500b57cec5SDimitry Andric         });
451fe6060f1SDimitry Andric         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
4528bcb0991SDimitry Andric                             *TargetSymbol, Addend);
4530b57cec5SDimitry Andric       }
4540b57cec5SDimitry Andric     }
4550b57cec5SDimitry Andric     return Error::success();
4560b57cec5SDimitry Andric   }
4570b57cec5SDimitry Andric };
4580b57cec5SDimitry Andric 
buildGOTAndStubs_MachO_x86_64(LinkGraph & G)459349cc55cSDimitry Andric Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
460349cc55cSDimitry Andric   x86_64::GOTTableManager GOT;
461349cc55cSDimitry Andric   x86_64::PLTTableManager PLT(GOT);
462349cc55cSDimitry Andric   visitExistingEdges(G, GOT, PLT);
4635ffd83dbSDimitry Andric   return Error::success();
4645ffd83dbSDimitry Andric }
4655ffd83dbSDimitry Andric 
466349cc55cSDimitry Andric } // namespace
467349cc55cSDimitry Andric 
4680b57cec5SDimitry Andric namespace llvm {
4690b57cec5SDimitry Andric namespace jitlink {
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
4720b57cec5SDimitry Andric   friend class JITLinker<MachOJITLinker_x86_64>;
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric public:
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)4750b57cec5SDimitry Andric   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
476e8d8bef9SDimitry Andric                         std::unique_ptr<LinkGraph> G,
4770b57cec5SDimitry Andric                         PassConfiguration PassConfig)
478e8d8bef9SDimitry Andric       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const481fe6060f1SDimitry Andric   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
482349cc55cSDimitry Andric     return x86_64::applyFixup(G, B, E, nullptr);
4830b57cec5SDimitry Andric   }
4840b57cec5SDimitry Andric };
4850b57cec5SDimitry Andric 
486e8d8bef9SDimitry Andric Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer)487e8d8bef9SDimitry Andric createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
488e8d8bef9SDimitry Andric   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
489e8d8bef9SDimitry Andric   if (!MachOObj)
490e8d8bef9SDimitry Andric     return MachOObj.takeError();
49106c3fb27SDimitry Andric 
49206c3fb27SDimitry Andric   auto Features = (*MachOObj)->getFeatures();
49306c3fb27SDimitry Andric   if (!Features)
49406c3fb27SDimitry Andric     return Features.takeError();
49506c3fb27SDimitry Andric 
49606c3fb27SDimitry Andric   return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features))
49706c3fb27SDimitry Andric       .buildGraph();
498e8d8bef9SDimitry Andric }
4990b57cec5SDimitry Andric 
link_MachO_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)500e8d8bef9SDimitry Andric void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
501e8d8bef9SDimitry Andric                        std::unique_ptr<JITLinkContext> Ctx) {
502e8d8bef9SDimitry Andric 
503e8d8bef9SDimitry Andric   PassConfiguration Config;
504e8d8bef9SDimitry Andric 
505e8d8bef9SDimitry Andric   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
5065f757f3fSDimitry Andric     // Add eh-frame passes.
507fe6060f1SDimitry Andric     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
508fe6060f1SDimitry Andric     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
509480093f4SDimitry Andric 
510349cc55cSDimitry Andric     // Add compact unwind splitter pass.
511349cc55cSDimitry Andric     Config.PrePrunePasses.push_back(
512349cc55cSDimitry Andric         CompactUnwindSplitter("__LD,__compact_unwind"));
513349cc55cSDimitry Andric 
5140b57cec5SDimitry Andric     // Add a mark-live pass.
515e8d8bef9SDimitry Andric     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
5160b57cec5SDimitry Andric       Config.PrePrunePasses.push_back(std::move(MarkLive));
5170b57cec5SDimitry Andric     else
5188bcb0991SDimitry Andric       Config.PrePrunePasses.push_back(markAllSymbolsLive);
5190b57cec5SDimitry Andric 
520*0fca6ea1SDimitry Andric     // Resolve any external section start / end symbols.
521*0fca6ea1SDimitry Andric     Config.PostAllocationPasses.push_back(
522*0fca6ea1SDimitry Andric         createDefineExternalSectionStartAndEndSymbolsPass(
523*0fca6ea1SDimitry Andric             identifyMachOSectionStartAndEndSymbols));
524*0fca6ea1SDimitry Andric 
5250b57cec5SDimitry Andric     // Add an in-place GOT/Stubs pass.
526349cc55cSDimitry Andric     Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
5275ffd83dbSDimitry Andric 
5285ffd83dbSDimitry Andric     // Add GOT/Stubs optimizer pass.
529349cc55cSDimitry Andric     Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric 
532fe6060f1SDimitry Andric   if (auto Err = Ctx->modifyPassConfig(*G, Config))
5330b57cec5SDimitry Andric     return Ctx->notifyFailed(std::move(Err));
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric   // Construct a JITLinker and run the link function.
536e8d8bef9SDimitry Andric   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric 
createEHFrameSplitterPass_MachO_x86_64()539fe6060f1SDimitry Andric LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
54081ad6265SDimitry Andric   return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
5410b57cec5SDimitry Andric }
542fe6060f1SDimitry Andric 
createEHFrameEdgeFixerPass_MachO_x86_64()543fe6060f1SDimitry Andric LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
544fe6060f1SDimitry Andric   return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
54581ad6265SDimitry Andric                           x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
54681ad6265SDimitry Andric                           x86_64::Delta64, x86_64::NegDelta32);
5470b57cec5SDimitry Andric }
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric } // end namespace jitlink
5500b57cec5SDimitry Andric } // end namespace llvm
551