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