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
20using namespace llvm;
21using namespace llvm::jitlink;
22using namespace llvm::jitlink::MachO_x86_64_Edges;
23
24namespace {
25
26class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
27public:
28  MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
29      : MachOLinkGraphBuilder(Obj) {}
30
31private:
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
350class MachO_x86_64_GOTAndStubsBuilder
351    : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
352public:
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
394private:
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
426const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
427    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
428const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
429    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
430} // namespace
431
432namespace llvm {
433namespace jitlink {
434
435class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
436  friend class JITLinker<MachOJITLinker_x86_64>;
437
438public:
439  MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
440                        PassConfiguration PassConfig)
441      : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
442
443private:
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
552void 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
582StringRef 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