1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
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/x86-64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
14 
15 #include "BasicGOTAndStubsBuilder.h"
16 #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_x86_64_Edges;
23 
24 namespace {
25 
26 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
27 public:
28   MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
29       : MachOLinkGraphBuilder(Obj) {}
30 
31 private:
32   static Expected<MachOX86RelocationKind>
33   getRelocationKind(const MachO::relocation_info &RI) {
34     switch (RI.r_type) {
35     case MachO::X86_64_RELOC_UNSIGNED:
36       if (!RI.r_pcrel) {
37         if (RI.r_length == 3)
38           return RI.r_extern ? Pointer64 : Pointer64Anon;
39         else if (RI.r_extern && RI.r_length == 2)
40           return Pointer32;
41       }
42       break;
43     case MachO::X86_64_RELOC_SIGNED:
44       if (RI.r_pcrel && RI.r_length == 2)
45         return RI.r_extern ? PCRel32 : PCRel32Anon;
46       break;
47     case MachO::X86_64_RELOC_BRANCH:
48       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
49         return Branch32;
50       break;
51     case MachO::X86_64_RELOC_GOT_LOAD:
52       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
53         return PCRel32GOTLoad;
54       break;
55     case MachO::X86_64_RELOC_GOT:
56       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
57         return PCRel32GOT;
58       break;
59     case MachO::X86_64_RELOC_SUBTRACTOR:
60       // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
61       // Initially represent SUBTRACTOR relocations with 'Delta<W>'. They may
62       // be turned into NegDelta<W> by parsePairRelocation.
63       if (!RI.r_pcrel && RI.r_extern) {
64         if (RI.r_length == 2)
65           return Delta32;
66         else if (RI.r_length == 3)
67           return Delta64;
68       }
69       break;
70     case MachO::X86_64_RELOC_SIGNED_1:
71       if (RI.r_pcrel && RI.r_length == 2)
72         return RI.r_extern ? PCRel32Minus1 : PCRel32Minus1Anon;
73       break;
74     case MachO::X86_64_RELOC_SIGNED_2:
75       if (RI.r_pcrel && RI.r_length == 2)
76         return RI.r_extern ? PCRel32Minus2 : PCRel32Minus2Anon;
77       break;
78     case MachO::X86_64_RELOC_SIGNED_4:
79       if (RI.r_pcrel && RI.r_length == 2)
80         return RI.r_extern ? PCRel32Minus4 : PCRel32Minus4Anon;
81       break;
82     case MachO::X86_64_RELOC_TLV:
83       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
84         return PCRel32TLV;
85       break;
86     }
87 
88     return make_error<JITLinkError>(
89         "Unsupported x86-64 relocation: address=" +
90         formatv("{0:x8}", RI.r_address) +
91         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
92         ", kind=" + formatv("{0:x1}", RI.r_type) +
93         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
94         ", extern=" + (RI.r_extern ? "true" : "false") +
95         ", length=" + formatv("{0:d}", RI.r_length));
96   }
97 
98   MachO::relocation_info
99   getRelocationInfo(const object::relocation_iterator RelItr) {
100     MachO::any_relocation_info ARI =
101         getObject().getRelocation(RelItr->getRawDataRefImpl());
102     MachO::relocation_info RI;
103     memcpy(&RI, &ARI, sizeof(MachO::relocation_info));
104     return RI;
105   }
106 
107   using PairRelocInfo = std::tuple<MachOX86RelocationKind, Symbol *, uint64_t>;
108 
109   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
110   // returns the edge kind and addend to be used.
111   Expected<PairRelocInfo>
112   parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
113                       const MachO::relocation_info &SubRI,
114                       JITTargetAddress FixupAddress, const char *FixupContent,
115                       object::relocation_iterator &UnsignedRelItr,
116                       object::relocation_iterator &RelEnd) {
117     using namespace support;
118 
119     assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
120             (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
121            "Subtractor kind should match length");
122     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
123     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
124 
125     if (UnsignedRelItr == RelEnd)
126       return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
127                                       "UNSIGNED relocation");
128 
129     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
130 
131     if (SubRI.r_address != UnsignedRI.r_address)
132       return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
133                                       "point to different addresses");
134 
135     if (SubRI.r_length != UnsignedRI.r_length)
136       return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
137                                       "UNSIGNED reloc must match");
138 
139     Symbol *FromSymbol;
140     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
141       FromSymbol = FromSymbolOrErr->GraphSymbol;
142     else
143       return FromSymbolOrErr.takeError();
144 
145     // Read the current fixup value.
146     uint64_t FixupValue = 0;
147     if (SubRI.r_length == 3)
148       FixupValue = *(const little64_t *)FixupContent;
149     else
150       FixupValue = *(const little32_t *)FixupContent;
151 
152     // Find 'ToSymbol' using symbol number or address, depending on whether the
153     // paired UNSIGNED relocation is extern.
154     Symbol *ToSymbol = nullptr;
155     if (UnsignedRI.r_extern) {
156       // Find target symbol by symbol index.
157       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
158         ToSymbol = ToSymbolOrErr->GraphSymbol;
159       else
160         return ToSymbolOrErr.takeError();
161     } else {
162       if (auto ToSymbolOrErr = findSymbolByAddress(FixupValue))
163         ToSymbol = &*ToSymbolOrErr;
164       else
165         return ToSymbolOrErr.takeError();
166       FixupValue -= ToSymbol->getAddress();
167     }
168 
169     MachOX86RelocationKind DeltaKind;
170     Symbol *TargetSymbol;
171     uint64_t Addend;
172     if (&BlockToFix == &FromSymbol->getAddressable()) {
173       TargetSymbol = ToSymbol;
174       DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
175       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
176       // FIXME: handle extern 'from'.
177     } else if (&BlockToFix == &ToSymbol->getAddressable()) {
178       TargetSymbol = FromSymbol;
179       DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
180       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
181     } else {
182       // BlockToFix was neither FromSymbol nor ToSymbol.
183       return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
184                                       "either 'A' or 'B' (or a symbol in one "
185                                       "of their alt-entry chains)");
186     }
187 
188     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
189   }
190 
191   Error addRelocations() override {
192     using namespace support;
193     auto &Obj = getObject();
194 
195     for (auto &S : Obj.sections()) {
196 
197       JITTargetAddress SectionAddress = S.getAddress();
198 
199       if (S.isVirtual()) {
200         if (S.relocation_begin() != S.relocation_end())
201           return make_error<JITLinkError>("Virtual section contains "
202                                           "relocations");
203         continue;
204       }
205 
206       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
207            RelItr != RelEnd; ++RelItr) {
208 
209         MachO::relocation_info RI = getRelocationInfo(RelItr);
210 
211         // Sanity check the relocation kind.
212         auto Kind = getRelocationKind(RI);
213         if (!Kind)
214           return Kind.takeError();
215 
216         // Find the address of the value to fix up.
217         JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
218 
219         LLVM_DEBUG({
220           dbgs() << "Processing relocation at "
221                  << format("0x%016" PRIx64, FixupAddress) << "\n";
222         });
223 
224         // Find the block that the fixup points to.
225         Block *BlockToFix = nullptr;
226         {
227           auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
228           if (!SymbolToFixOrErr)
229             return SymbolToFixOrErr.takeError();
230           BlockToFix = &SymbolToFixOrErr->getBlock();
231         }
232 
233         if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
234             BlockToFix->getAddress() + BlockToFix->getContent().size())
235           return make_error<JITLinkError>(
236               "Relocation extends past end of fixup block");
237 
238         // Get a pointer to the fixup content.
239         const char *FixupContent = BlockToFix->getContent().data() +
240                                    (FixupAddress - BlockToFix->getAddress());
241 
242         // The target symbol and addend will be populated by the switch below.
243         Symbol *TargetSymbol = nullptr;
244         uint64_t Addend = 0;
245 
246         switch (*Kind) {
247         case Branch32:
248         case PCRel32:
249         case PCRel32GOTLoad:
250         case PCRel32GOT:
251           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
252             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
253           else
254             return TargetSymbolOrErr.takeError();
255           Addend = *(const little32_t *)FixupContent;
256           break;
257         case Pointer32:
258           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
259             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
260           else
261             return TargetSymbolOrErr.takeError();
262           Addend = *(const ulittle32_t *)FixupContent;
263           break;
264         case Pointer64:
265           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
266             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
267           else
268             return TargetSymbolOrErr.takeError();
269           Addend = *(const ulittle64_t *)FixupContent;
270           break;
271         case Pointer64Anon: {
272           JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
273           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
274             TargetSymbol = &*TargetSymbolOrErr;
275           else
276             return TargetSymbolOrErr.takeError();
277           Addend = TargetAddress - TargetSymbol->getAddress();
278           break;
279         }
280         case PCRel32Minus1:
281         case PCRel32Minus2:
282         case PCRel32Minus4:
283           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
284             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
285           else
286             return TargetSymbolOrErr.takeError();
287           Addend = *(const little32_t *)FixupContent +
288                    (1 << (*Kind - PCRel32Minus1));
289           break;
290         case PCRel32Anon: {
291           JITTargetAddress TargetAddress =
292               FixupAddress + 4 + *(const little32_t *)FixupContent;
293           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
294             TargetSymbol = &*TargetSymbolOrErr;
295           else
296             return TargetSymbolOrErr.takeError();
297           Addend = TargetAddress - TargetSymbol->getAddress();
298           break;
299         }
300         case PCRel32Minus1Anon:
301         case PCRel32Minus2Anon:
302         case PCRel32Minus4Anon: {
303           JITTargetAddress Delta =
304               static_cast<JITTargetAddress>(1ULL << (*Kind - PCRel32Minus1Anon));
305           JITTargetAddress TargetAddress =
306               FixupAddress + 4 + Delta + *(const little32_t *)FixupContent;
307           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
308             TargetSymbol = &*TargetSymbolOrErr;
309           else
310             return TargetSymbolOrErr.takeError();
311           Addend = TargetAddress - TargetSymbol->getAddress();
312           break;
313         }
314         case Delta32:
315         case Delta64: {
316           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
317           // parsePairRelocation handles the paired reloc, and returns the
318           // edge kind to be used (either Delta32/Delta64, or
319           // NegDelta32/NegDelta64, depending on the direction of the
320           // subtraction) along with the addend.
321           auto PairInfo =
322               parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
323                                   FixupContent, ++RelItr, RelEnd);
324           if (!PairInfo)
325             return PairInfo.takeError();
326           std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
327           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
328           break;
329         }
330         default:
331           llvm_unreachable("Special relocation kind should not appear in "
332                            "mach-o file");
333         }
334 
335         LLVM_DEBUG({
336           Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
337                   Addend);
338           printEdge(dbgs(), *BlockToFix, GE,
339                     getMachOX86RelocationKindName(*Kind));
340           dbgs() << "\n";
341         });
342         BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
343                             *TargetSymbol, Addend);
344       }
345     }
346     return Error::success();
347   }
348 };
349 
350 class MachO_x86_64_GOTAndStubsBuilder
351     : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
352 public:
353   MachO_x86_64_GOTAndStubsBuilder(LinkGraph &G)
354       : BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(G) {}
355 
356   bool isGOTEdge(Edge &E) const {
357     return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
358   }
359 
360   Symbol &createGOTEntry(Symbol &Target) {
361     auto &GOTEntryBlock = G.createContentBlock(
362         getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
363     GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
364     return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
365   }
366 
367   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
368     assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
369            "Not a GOT edge?");
370     E.setKind(PCRel32);
371     E.setTarget(GOTEntry);
372     // Leave the edge addend as-is.
373   }
374 
375   bool isExternalBranchEdge(Edge &E) {
376     return E.getKind() == Branch32 && !E.getTarget().isDefined();
377   }
378 
379   Symbol &createStub(Symbol &Target) {
380     auto &StubContentBlock =
381         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
382     // Re-use GOT entries for stub targets.
383     auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
384     StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, 0);
385     return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
386   }
387 
388   void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
389     assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
390     assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
391     E.setTarget(Stub);
392   }
393 
394 private:
395   Section &getGOTSection() {
396     if (!GOTSection)
397       GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
398     return *GOTSection;
399   }
400 
401   Section &getStubsSection() {
402     if (!StubsSection) {
403       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
404           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
405       StubsSection = &G.createSection("$__STUBS", StubsProt);
406     }
407     return *StubsSection;
408   }
409 
410   StringRef getGOTEntryBlockContent() {
411     return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
412                      sizeof(NullGOTEntryContent));
413   }
414 
415   StringRef getStubBlockContent() {
416     return StringRef(reinterpret_cast<const char *>(StubContent),
417                      sizeof(StubContent));
418   }
419 
420   static const uint8_t NullGOTEntryContent[8];
421   static const uint8_t StubContent[6];
422   Section *GOTSection = nullptr;
423   Section *StubsSection = nullptr;
424 };
425 
426 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
427     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
428 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
429     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
430 } // namespace
431 
432 namespace llvm {
433 namespace jitlink {
434 
435 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
436   friend class JITLinker<MachOJITLinker_x86_64>;
437 
438 public:
439   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
440                         PassConfiguration PassConfig)
441       : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
442 
443 private:
444   StringRef getEdgeKindName(Edge::Kind R) const override {
445     return getMachOX86RelocationKindName(R);
446   }
447 
448   Expected<std::unique_ptr<LinkGraph>>
449   buildGraph(MemoryBufferRef ObjBuffer) override {
450     auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
451     if (!MachOObj)
452       return MachOObj.takeError();
453     return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
454   }
455 
456   static Error targetOutOfRangeError(const Block &B, const Edge &E) {
457     std::string ErrMsg;
458     {
459       raw_string_ostream ErrStream(ErrMsg);
460       ErrStream << "Relocation target out of range: ";
461       printEdge(ErrStream, B, E, getMachOX86RelocationKindName(E.getKind()));
462       ErrStream << "\n";
463     }
464     return make_error<JITLinkError>(std::move(ErrMsg));
465   }
466 
467   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
468 
469     using namespace support;
470 
471     char *FixupPtr = BlockWorkingMem + E.getOffset();
472     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
473 
474     switch (E.getKind()) {
475     case Branch32:
476     case PCRel32:
477     case PCRel32Anon: {
478       int64_t Value =
479           E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
480       if (Value < std::numeric_limits<int32_t>::min() ||
481           Value > std::numeric_limits<int32_t>::max())
482         return targetOutOfRangeError(B, E);
483       *(little32_t *)FixupPtr = Value;
484       break;
485     }
486     case Pointer64:
487     case Pointer64Anon: {
488       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
489       *(ulittle64_t *)FixupPtr = Value;
490       break;
491     }
492     case PCRel32Minus1:
493     case PCRel32Minus2:
494     case PCRel32Minus4: {
495       int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
496       int64_t Value =
497           E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
498       if (Value < std::numeric_limits<int32_t>::min() ||
499           Value > std::numeric_limits<int32_t>::max())
500         return targetOutOfRangeError(B, E);
501       *(little32_t *)FixupPtr = Value;
502       break;
503     }
504     case PCRel32Minus1Anon:
505     case PCRel32Minus2Anon:
506     case PCRel32Minus4Anon: {
507       int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
508       int64_t Value =
509           E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
510       if (Value < std::numeric_limits<int32_t>::min() ||
511           Value > std::numeric_limits<int32_t>::max())
512         return targetOutOfRangeError(B, E);
513       *(little32_t *)FixupPtr = Value;
514       break;
515     }
516     case Delta32:
517     case Delta64:
518     case NegDelta32:
519     case NegDelta64: {
520       int64_t Value;
521       if (E.getKind() == Delta32 || E.getKind() == Delta64)
522         Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
523       else
524         Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
525 
526       if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
527         if (Value < std::numeric_limits<int32_t>::min() ||
528             Value > std::numeric_limits<int32_t>::max())
529           return targetOutOfRangeError(B, E);
530         *(little32_t *)FixupPtr = Value;
531       } else
532         *(little64_t *)FixupPtr = Value;
533       break;
534     }
535     case Pointer32: {
536       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
537       if (Value > std::numeric_limits<uint32_t>::max())
538         return targetOutOfRangeError(B, E);
539       *(ulittle32_t *)FixupPtr = Value;
540       break;
541     }
542     default:
543       llvm_unreachable("Unrecognized edge kind");
544     }
545 
546     return Error::success();
547   }
548 
549   uint64_t NullValue = 0;
550 };
551 
552 void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
553   PassConfiguration Config;
554   Triple TT("x86_64-apple-macosx");
555 
556   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
557     // Add eh-frame passses.
558     Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame"));
559     Config.PrePrunePasses.push_back(
560         EHFrameEdgeFixer("__eh_frame", NegDelta32, Delta64, Delta64));
561 
562     // Add a mark-live pass.
563     if (auto MarkLive = Ctx->getMarkLivePass(TT))
564       Config.PrePrunePasses.push_back(std::move(MarkLive));
565     else
566       Config.PrePrunePasses.push_back(markAllSymbolsLive);
567 
568     // Add an in-place GOT/Stubs pass.
569     Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
570       MachO_x86_64_GOTAndStubsBuilder(G).run();
571       return Error::success();
572     });
573   }
574 
575   if (auto Err = Ctx->modifyPassConfig(TT, Config))
576     return Ctx->notifyFailed(std::move(Err));
577 
578   // Construct a JITLinker and run the link function.
579   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
580 }
581 
582 StringRef getMachOX86RelocationKindName(Edge::Kind R) {
583   switch (R) {
584   case Branch32:
585     return "Branch32";
586   case Pointer32:
587     return "Pointer32";
588   case Pointer64:
589     return "Pointer64";
590   case Pointer64Anon:
591     return "Pointer64Anon";
592   case PCRel32:
593     return "PCRel32";
594   case PCRel32Minus1:
595     return "PCRel32Minus1";
596   case PCRel32Minus2:
597     return "PCRel32Minus2";
598   case PCRel32Minus4:
599     return "PCRel32Minus4";
600   case PCRel32Anon:
601     return "PCRel32Anon";
602   case PCRel32Minus1Anon:
603     return "PCRel32Minus1Anon";
604   case PCRel32Minus2Anon:
605     return "PCRel32Minus2Anon";
606   case PCRel32Minus4Anon:
607     return "PCRel32Minus4Anon";
608   case PCRel32GOTLoad:
609     return "PCRel32GOTLoad";
610   case PCRel32GOT:
611     return "PCRel32GOT";
612   case PCRel32TLV:
613     return "PCRel32TLV";
614   case Delta32:
615     return "Delta32";
616   case Delta64:
617     return "Delta64";
618   case NegDelta32:
619     return "NegDelta32";
620   case NegDelta64:
621     return "NegDelta64";
622   default:
623     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
624   }
625 }
626 
627 } // end namespace jitlink
628 } // end namespace llvm
629