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 609