[Alignment][NFC] Use Align with TargetLowering::setMinFunctionAlignment
[llvm-core.git] / lib / ExecutionEngine / JITLink / MachO_x86_64.cpp
blob52481f8436e9e28c58bbfd3adff33505c6afaf1f
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.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
15 #include "BasicGOTAndStubsBuilder.h"
16 #include "MachOAtomGraphBuilder.h"
18 #define DEBUG_TYPE "jitlink"
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 using namespace llvm::jitlink::MachO_x86_64_Edges;
24 namespace {
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 });
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) {
44 if (RI.r_length == 3)
45 return RI.r_extern ? Pointer64 : Pointer64Anon;
46 else if (RI.r_extern && RI.r_length == 2)
47 return Pointer32;
49 break;
50 case MachO::X86_64_RELOC_SIGNED:
51 if (RI.r_pcrel && RI.r_length == 2)
52 return RI.r_extern ? PCRel32 : PCRel32Anon;
53 break;
54 case MachO::X86_64_RELOC_BRANCH:
55 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
56 return Branch32;
57 break;
58 case MachO::X86_64_RELOC_GOT_LOAD:
59 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
60 return PCRel32GOTLoad;
61 break;
62 case MachO::X86_64_RELOC_GOT:
63 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
64 return PCRel32GOT;
65 break;
66 case MachO::X86_64_RELOC_SUBTRACTOR:
67 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
68 // Initially represent SUBTRACTOR relocations with 'Delta<W>'. They may
69 // be turned into NegDelta<W> by parsePairRelocation.
70 if (!RI.r_pcrel && RI.r_extern) {
71 if (RI.r_length == 2)
72 return Delta32;
73 else if (RI.r_length == 3)
74 return Delta64;
76 break;
77 case MachO::X86_64_RELOC_SIGNED_1:
78 if (RI.r_pcrel && RI.r_length == 2)
79 return RI.r_extern ? PCRel32Minus1 : PCRel32Minus1Anon;
80 break;
81 case MachO::X86_64_RELOC_SIGNED_2:
82 if (RI.r_pcrel && RI.r_length == 2)
83 return RI.r_extern ? PCRel32Minus2 : PCRel32Minus2Anon;
84 break;
85 case MachO::X86_64_RELOC_SIGNED_4:
86 if (RI.r_pcrel && RI.r_length == 2)
87 return RI.r_extern ? PCRel32Minus4 : PCRel32Minus4Anon;
88 break;
89 case MachO::X86_64_RELOC_TLV:
90 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
91 return PCRel32TLV;
92 break;
95 return make_error<JITLinkError>(
96 "Unsupported x86-64 relocation: address=" +
97 formatv("{0:x8}", RI.r_address) +
98 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
99 ", kind=" + formatv("{0:x1}", RI.r_type) +
100 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
101 ", extern=" + (RI.r_extern ? "true" : "false") +
102 ", length=" + formatv("{0:d}", RI.r_length));
105 Expected<Atom &> findAtomBySymbolIndex(const MachO::relocation_info &RI) {
106 auto &Obj = getObject();
107 if (RI.r_symbolnum >= NumSymbols)
108 return make_error<JITLinkError>("Symbol index out of range");
109 auto SymI = Obj.getSymbolByIndex(RI.r_symbolnum);
110 auto Name = SymI->getName();
111 if (!Name)
112 return Name.takeError();
113 return getGraph().getAtomByName(*Name);
116 MachO::relocation_info
117 getRelocationInfo(const object::relocation_iterator RelItr) {
118 MachO::any_relocation_info ARI =
119 getObject().getRelocation(RelItr->getRawDataRefImpl());
120 MachO::relocation_info RI;
121 memcpy(&RI, &ARI, sizeof(MachO::relocation_info));
122 return RI;
125 using PairRelocInfo = std::tuple<MachOX86RelocationKind, Atom *, uint64_t>;
127 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
128 // returns the edge kind and addend to be used.
129 Expected<PairRelocInfo>
130 parsePairRelocation(DefinedAtom &AtomToFix, Edge::Kind SubtractorKind,
131 const MachO::relocation_info &SubRI,
132 JITTargetAddress FixupAddress, const char *FixupContent,
133 object::relocation_iterator &UnsignedRelItr,
134 object::relocation_iterator &RelEnd) {
135 using namespace support;
137 assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
138 (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
139 "Subtractor kind should match length");
140 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
141 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
143 if (UnsignedRelItr == RelEnd)
144 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
145 "UNSIGNED relocation");
147 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
149 if (SubRI.r_address != UnsignedRI.r_address)
150 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
151 "point to different addresses");
153 if (SubRI.r_length != UnsignedRI.r_length)
154 return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
155 "UNSIGNED reloc must match");
157 auto FromAtom = findAtomBySymbolIndex(SubRI);
158 if (!FromAtom)
159 return FromAtom.takeError();
161 // Read the current fixup value.
162 uint64_t FixupValue = 0;
163 if (SubRI.r_length == 3)
164 FixupValue = *(const little64_t *)FixupContent;
165 else
166 FixupValue = *(const little32_t *)FixupContent;
168 // Find 'ToAtom' using symbol number or address, depending on whether the
169 // paired UNSIGNED relocation is extern.
170 Atom *ToAtom = nullptr;
171 if (UnsignedRI.r_extern) {
172 // Find target atom by symbol index.
173 if (auto ToAtomOrErr = findAtomBySymbolIndex(UnsignedRI))
174 ToAtom = &*ToAtomOrErr;
175 else
176 return ToAtomOrErr.takeError();
177 } else {
178 if (auto ToAtomOrErr = getGraph().findAtomByAddress(FixupValue))
179 ToAtom = &*ToAtomOrErr;
180 else
181 return ToAtomOrErr.takeError();
182 FixupValue -= ToAtom->getAddress();
185 MachOX86RelocationKind DeltaKind;
186 Atom *TargetAtom;
187 uint64_t Addend;
188 if (areLayoutLocked(AtomToFix, *FromAtom)) {
189 TargetAtom = ToAtom;
190 DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
191 Addend = FixupValue + (FixupAddress - FromAtom->getAddress());
192 // FIXME: handle extern 'from'.
193 } else if (areLayoutLocked(AtomToFix, *ToAtom)) {
194 TargetAtom = &*FromAtom;
195 DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
196 Addend = FixupValue - (FixupAddress - ToAtom->getAddress());
197 } else {
198 // AtomToFix was neither FromAtom nor ToAtom.
199 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
200 "either 'A' or 'B' (or an atom in one "
201 "of their alt-entry groups)");
204 return PairRelocInfo(DeltaKind, TargetAtom, Addend);
207 Error addRelocations() override {
208 using namespace support;
209 auto &G = getGraph();
210 auto &Obj = getObject();
212 for (auto &S : Obj.sections()) {
214 JITTargetAddress SectionAddress = S.getAddress();
216 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
217 RelItr != RelEnd; ++RelItr) {
219 MachO::relocation_info RI = getRelocationInfo(RelItr);
221 // Sanity check the relocation kind.
222 auto Kind = getRelocationKind(RI);
223 if (!Kind)
224 return Kind.takeError();
226 // Find the address of the value to fix up.
227 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
229 LLVM_DEBUG({
230 dbgs() << "Processing relocation at "
231 << format("0x%016" PRIx64, FixupAddress) << "\n";
234 // Find the atom that the fixup points to.
235 DefinedAtom *AtomToFix = nullptr;
237 auto AtomToFixOrErr = G.findAtomByAddress(FixupAddress);
238 if (!AtomToFixOrErr)
239 return AtomToFixOrErr.takeError();
240 AtomToFix = &*AtomToFixOrErr;
243 if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
244 AtomToFix->getAddress() + AtomToFix->getContent().size())
245 return make_error<JITLinkError>(
246 "Relocation content extends past end of fixup atom");
248 // Get a pointer to the fixup content.
249 const char *FixupContent = AtomToFix->getContent().data() +
250 (FixupAddress - AtomToFix->getAddress());
252 // The target atom and addend will be populated by the switch below.
253 Atom *TargetAtom = nullptr;
254 uint64_t Addend = 0;
256 switch (*Kind) {
257 case Branch32:
258 case PCRel32:
259 case PCRel32GOTLoad:
260 case PCRel32GOT:
261 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
262 TargetAtom = &*TargetAtomOrErr;
263 else
264 return TargetAtomOrErr.takeError();
265 Addend = *(const ulittle32_t *)FixupContent;
266 break;
267 case Pointer32:
268 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
269 TargetAtom = &*TargetAtomOrErr;
270 else
271 return TargetAtomOrErr.takeError();
272 Addend = *(const ulittle32_t *)FixupContent;
273 break;
274 case Pointer64:
275 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
276 TargetAtom = &*TargetAtomOrErr;
277 else
278 return TargetAtomOrErr.takeError();
279 Addend = *(const ulittle64_t *)FixupContent;
280 break;
281 case Pointer64Anon: {
282 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
283 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
284 TargetAtom = &*TargetAtomOrErr;
285 else
286 return TargetAtomOrErr.takeError();
287 Addend = TargetAddress - TargetAtom->getAddress();
288 break;
290 case PCRel32Minus1:
291 case PCRel32Minus2:
292 case PCRel32Minus4:
293 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
294 TargetAtom = &*TargetAtomOrErr;
295 else
296 return TargetAtomOrErr.takeError();
297 Addend = *(const ulittle32_t *)FixupContent +
298 (1 << (*Kind - PCRel32Minus1));
299 break;
300 case PCRel32Anon: {
301 JITTargetAddress TargetAddress =
302 FixupAddress + 4 + *(const ulittle32_t *)FixupContent;
303 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
304 TargetAtom = &*TargetAtomOrErr;
305 else
306 return TargetAtomOrErr.takeError();
307 Addend = TargetAddress - TargetAtom->getAddress();
308 break;
310 case PCRel32Minus1Anon:
311 case PCRel32Minus2Anon:
312 case PCRel32Minus4Anon: {
313 JITTargetAddress Delta =
314 static_cast<JITTargetAddress>(1ULL << (*Kind - PCRel32Minus1Anon));
315 JITTargetAddress TargetAddress =
316 FixupAddress + 4 + Delta + *(const ulittle32_t *)FixupContent;
317 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
318 TargetAtom = &*TargetAtomOrErr;
319 else
320 return TargetAtomOrErr.takeError();
321 Addend = TargetAddress - TargetAtom->getAddress();
322 break;
324 case Delta32:
325 case Delta64: {
326 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
327 // parsePairRelocation handles the paired reloc, and returns the
328 // edge kind to be used (either Delta32/Delta64, or
329 // NegDelta32/NegDelta64, depending on the direction of the
330 // subtraction) along with the addend.
331 auto PairInfo =
332 parsePairRelocation(*AtomToFix, *Kind, RI, FixupAddress,
333 FixupContent, ++RelItr, RelEnd);
334 if (!PairInfo)
335 return PairInfo.takeError();
336 std::tie(*Kind, TargetAtom, Addend) = *PairInfo;
337 assert(TargetAtom && "No target atom from parsePairRelocation?");
338 break;
340 default:
341 llvm_unreachable("Special relocation kind should not appear in "
342 "mach-o file");
345 LLVM_DEBUG({
346 Edge GE(*Kind, FixupAddress - AtomToFix->getAddress(), *TargetAtom,
347 Addend);
348 printEdge(dbgs(), *AtomToFix, GE,
349 getMachOX86RelocationKindName(*Kind));
350 dbgs() << "\n";
352 AtomToFix->addEdge(*Kind, FixupAddress - AtomToFix->getAddress(),
353 *TargetAtom, Addend);
356 return Error::success();
359 unsigned NumSymbols = 0;
362 class MachO_x86_64_GOTAndStubsBuilder
363 : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
364 public:
365 MachO_x86_64_GOTAndStubsBuilder(AtomGraph &G)
366 : BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(G) {}
368 bool isGOTEdge(Edge &E) const {
369 return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
372 DefinedAtom &createGOTEntry(Atom &Target) {
373 auto &GOTEntryAtom = G.addAnonymousAtom(getGOTSection(), 0x0, 8);
374 GOTEntryAtom.setContent(
375 StringRef(reinterpret_cast<const char *>(NullGOTEntryContent), 8));
376 GOTEntryAtom.addEdge(Pointer64, 0, Target, 0);
377 return GOTEntryAtom;
380 void fixGOTEdge(Edge &E, Atom &GOTEntry) {
381 assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
382 "Not a GOT edge?");
383 E.setKind(PCRel32);
384 E.setTarget(GOTEntry);
385 // Leave the edge addend as-is.
388 bool isExternalBranchEdge(Edge &E) {
389 return E.getKind() == Branch32 && !E.getTarget().isDefined();
392 DefinedAtom &createStub(Atom &Target) {
393 auto &StubAtom = G.addAnonymousAtom(getStubsSection(), 0x0, 2);
394 StubAtom.setContent(
395 StringRef(reinterpret_cast<const char *>(StubContent), 6));
397 // Re-use GOT entries for stub targets.
398 auto &GOTEntryAtom = getGOTEntryAtom(Target);
399 StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0);
401 return StubAtom;
404 void fixExternalBranchEdge(Edge &E, Atom &Stub) {
405 assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
406 assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
407 E.setTarget(Stub);
410 private:
411 Section &getGOTSection() {
412 if (!GOTSection)
413 GOTSection = &G.createSection("$__GOT", 8, sys::Memory::MF_READ, false);
414 return *GOTSection;
417 Section &getStubsSection() {
418 if (!StubsSection) {
419 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
420 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
421 StubsSection = &G.createSection("$__STUBS", 8, StubsProt, false);
423 return *StubsSection;
426 static const uint8_t NullGOTEntryContent[8];
427 static const uint8_t StubContent[6];
428 Section *GOTSection = nullptr;
429 Section *StubsSection = nullptr;
432 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
433 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
434 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
435 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
436 } // namespace
438 namespace llvm {
439 namespace jitlink {
441 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
442 friend class JITLinker<MachOJITLinker_x86_64>;
444 public:
445 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
446 PassConfiguration PassConfig)
447 : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
449 private:
450 StringRef getEdgeKindName(Edge::Kind R) const override {
451 return getMachOX86RelocationKindName(R);
454 Expected<std::unique_ptr<AtomGraph>>
455 buildGraph(MemoryBufferRef ObjBuffer) override {
456 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
457 if (!MachOObj)
458 return MachOObj.takeError();
459 return MachOAtomGraphBuilder_x86_64(**MachOObj).buildGraph();
462 static Error targetOutOfRangeError(const Atom &A, const Edge &E) {
463 std::string ErrMsg;
465 raw_string_ostream ErrStream(ErrMsg);
466 ErrStream << "Relocation target out of range: ";
467 printEdge(ErrStream, A, E, getMachOX86RelocationKindName(E.getKind()));
468 ErrStream << "\n";
470 return make_error<JITLinkError>(std::move(ErrMsg));
473 Error applyFixup(DefinedAtom &A, const Edge &E, char *AtomWorkingMem) const {
474 using namespace support;
476 char *FixupPtr = AtomWorkingMem + E.getOffset();
477 JITTargetAddress FixupAddress = A.getAddress() + E.getOffset();
479 switch (E.getKind()) {
480 case Branch32:
481 case PCRel32:
482 case PCRel32Anon: {
483 int64_t Value =
484 E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
485 if (Value < std::numeric_limits<int32_t>::min() ||
486 Value > std::numeric_limits<int32_t>::max())
487 return targetOutOfRangeError(A, E);
488 *(little32_t *)FixupPtr = Value;
489 break;
491 case Pointer64:
492 case Pointer64Anon: {
493 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
494 *(ulittle64_t *)FixupPtr = Value;
495 break;
497 case PCRel32Minus1:
498 case PCRel32Minus2:
499 case PCRel32Minus4: {
500 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
501 int64_t Value =
502 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
503 if (Value < std::numeric_limits<int32_t>::min() ||
504 Value > std::numeric_limits<int32_t>::max())
505 return targetOutOfRangeError(A, E);
506 *(little32_t *)FixupPtr = Value;
507 break;
509 case PCRel32Minus1Anon:
510 case PCRel32Minus2Anon:
511 case PCRel32Minus4Anon: {
512 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
513 int64_t Value =
514 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
515 if (Value < std::numeric_limits<int32_t>::min() ||
516 Value > std::numeric_limits<int32_t>::max())
517 return targetOutOfRangeError(A, E);
518 *(little32_t *)FixupPtr = Value;
519 break;
521 case Delta32:
522 case Delta64:
523 case NegDelta32:
524 case NegDelta64: {
525 int64_t Value;
526 if (E.getKind() == Delta32 || E.getKind() == Delta64)
527 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
528 else
529 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
531 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
532 if (Value < std::numeric_limits<int32_t>::min() ||
533 Value > std::numeric_limits<int32_t>::max())
534 return targetOutOfRangeError(A, E);
535 *(little32_t *)FixupPtr = Value;
536 } else
537 *(little64_t *)FixupPtr = Value;
538 break;
540 case Pointer32: {
541 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
542 if (Value > std::numeric_limits<uint32_t>::max())
543 return targetOutOfRangeError(A, E);
544 *(ulittle32_t *)FixupPtr = Value;
545 break;
547 default:
548 llvm_unreachable("Unrecognized edge kind");
551 return Error::success();
554 uint64_t NullValue = 0;
557 void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
558 PassConfiguration Config;
559 Triple TT("x86_64-apple-macosx");
561 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
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(markAllAtomsLive);
568 // Add an in-place GOT/Stubs pass.
569 Config.PostPrunePasses.push_back([](AtomGraph &G) -> Error {
570 MachO_x86_64_GOTAndStubsBuilder(G).run();
571 return Error::success();
575 if (auto Err = Ctx->modifyPassConfig(TT, Config))
576 return Ctx->notifyFailed(std::move(Err));
578 // Construct a JITLinker and run the link function.
579 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
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));
627 } // end namespace jitlink
628 } // end namespace llvm