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 using PairRelocInfo = std::tuple<MachOX86RelocationKind, Symbol *, uint64_t>; 99 100 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, 101 // returns the edge kind and addend to be used. 102 Expected<PairRelocInfo> 103 parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind, 104 const MachO::relocation_info &SubRI, 105 JITTargetAddress FixupAddress, const char *FixupContent, 106 object::relocation_iterator &UnsignedRelItr, 107 object::relocation_iterator &RelEnd) { 108 using namespace support; 109 110 assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) || 111 (SubtractorKind == Delta64 && SubRI.r_length == 3)) && 112 "Subtractor kind should match length"); 113 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); 114 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); 115 116 if (UnsignedRelItr == RelEnd) 117 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired " 118 "UNSIGNED relocation"); 119 120 auto UnsignedRI = getRelocationInfo(UnsignedRelItr); 121 122 if (SubRI.r_address != UnsignedRI.r_address) 123 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED " 124 "point to different addresses"); 125 126 if (SubRI.r_length != UnsignedRI.r_length) 127 return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired " 128 "UNSIGNED reloc must match"); 129 130 Symbol *FromSymbol; 131 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) 132 FromSymbol = FromSymbolOrErr->GraphSymbol; 133 else 134 return FromSymbolOrErr.takeError(); 135 136 // Read the current fixup value. 137 uint64_t FixupValue = 0; 138 if (SubRI.r_length == 3) 139 FixupValue = *(const little64_t *)FixupContent; 140 else 141 FixupValue = *(const little32_t *)FixupContent; 142 143 // Find 'ToSymbol' using symbol number or address, depending on whether the 144 // paired UNSIGNED relocation is extern. 145 Symbol *ToSymbol = nullptr; 146 if (UnsignedRI.r_extern) { 147 // Find target symbol by symbol index. 148 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) 149 ToSymbol = ToSymbolOrErr->GraphSymbol; 150 else 151 return ToSymbolOrErr.takeError(); 152 } else { 153 if (auto ToSymbolOrErr = findSymbolByAddress(FixupValue)) 154 ToSymbol = &*ToSymbolOrErr; 155 else 156 return ToSymbolOrErr.takeError(); 157 FixupValue -= ToSymbol->getAddress(); 158 } 159 160 MachOX86RelocationKind DeltaKind; 161 Symbol *TargetSymbol; 162 uint64_t Addend; 163 if (&BlockToFix == &FromSymbol->getAddressable()) { 164 TargetSymbol = ToSymbol; 165 DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32; 166 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 167 // FIXME: handle extern 'from'. 168 } else if (&BlockToFix == &ToSymbol->getAddressable()) { 169 TargetSymbol = FromSymbol; 170 DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32; 171 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 172 } else { 173 // BlockToFix was neither FromSymbol nor ToSymbol. 174 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 175 "either 'A' or 'B' (or a symbol in one " 176 "of their alt-entry chains)"); 177 } 178 179 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 180 } 181 182 Error addRelocations() override { 183 using namespace support; 184 auto &Obj = getObject(); 185 186 for (auto &S : Obj.sections()) { 187 188 JITTargetAddress SectionAddress = S.getAddress(); 189 190 // Skip relocations virtual sections. 191 if (S.isVirtual()) { 192 if (S.relocation_begin() != S.relocation_end()) 193 return make_error<JITLinkError>("Virtual section contains " 194 "relocations"); 195 continue; 196 } 197 198 // Skip relocations for debug symbols. 199 { 200 auto &NSec = 201 getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 202 if (!NSec.GraphSection) { 203 LLVM_DEBUG({ 204 dbgs() << "Skipping relocations for MachO section " << NSec.SegName 205 << "/" << NSec.SectName 206 << " which has no associated graph section\n"; 207 }); 208 continue; 209 } 210 } 211 212 // Add relocations for section. 213 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 214 RelItr != RelEnd; ++RelItr) { 215 216 MachO::relocation_info RI = getRelocationInfo(RelItr); 217 218 // Sanity check the relocation kind. 219 auto Kind = getRelocationKind(RI); 220 if (!Kind) 221 return Kind.takeError(); 222 223 // Find the address of the value to fix up. 224 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address; 225 226 LLVM_DEBUG({ 227 dbgs() << "Processing relocation at " 228 << format("0x%016" PRIx64, FixupAddress) << "\n"; 229 }); 230 231 // Find the block that the fixup points to. 232 Block *BlockToFix = nullptr; 233 { 234 auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress); 235 if (!SymbolToFixOrErr) 236 return SymbolToFixOrErr.takeError(); 237 BlockToFix = &SymbolToFixOrErr->getBlock(); 238 } 239 240 if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) > 241 BlockToFix->getAddress() + BlockToFix->getContent().size()) 242 return make_error<JITLinkError>( 243 "Relocation extends past end of fixup block"); 244 245 // Get a pointer to the fixup content. 246 const char *FixupContent = BlockToFix->getContent().data() + 247 (FixupAddress - BlockToFix->getAddress()); 248 249 // The target symbol and addend will be populated by the switch below. 250 Symbol *TargetSymbol = nullptr; 251 uint64_t Addend = 0; 252 253 switch (*Kind) { 254 case Branch32: 255 case PCRel32: 256 case PCRel32GOTLoad: 257 case PCRel32GOT: 258 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 259 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 260 else 261 return TargetSymbolOrErr.takeError(); 262 Addend = *(const little32_t *)FixupContent; 263 break; 264 case Pointer32: 265 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 266 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 267 else 268 return TargetSymbolOrErr.takeError(); 269 Addend = *(const ulittle32_t *)FixupContent; 270 break; 271 case Pointer64: 272 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 273 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 274 else 275 return TargetSymbolOrErr.takeError(); 276 Addend = *(const ulittle64_t *)FixupContent; 277 break; 278 case Pointer64Anon: { 279 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent; 280 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 281 TargetSymbol = &*TargetSymbolOrErr; 282 else 283 return TargetSymbolOrErr.takeError(); 284 Addend = TargetAddress - TargetSymbol->getAddress(); 285 break; 286 } 287 case PCRel32Minus1: 288 case PCRel32Minus2: 289 case PCRel32Minus4: 290 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 291 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 292 else 293 return TargetSymbolOrErr.takeError(); 294 Addend = *(const little32_t *)FixupContent + 295 (1 << (*Kind - PCRel32Minus1)); 296 break; 297 case PCRel32Anon: { 298 JITTargetAddress TargetAddress = 299 FixupAddress + 4 + *(const little32_t *)FixupContent; 300 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 301 TargetSymbol = &*TargetSymbolOrErr; 302 else 303 return TargetSymbolOrErr.takeError(); 304 Addend = TargetAddress - TargetSymbol->getAddress(); 305 break; 306 } 307 case PCRel32Minus1Anon: 308 case PCRel32Minus2Anon: 309 case PCRel32Minus4Anon: { 310 JITTargetAddress Delta = 311 static_cast<JITTargetAddress>(1ULL << (*Kind - PCRel32Minus1Anon)); 312 JITTargetAddress TargetAddress = 313 FixupAddress + 4 + Delta + *(const little32_t *)FixupContent; 314 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 315 TargetSymbol = &*TargetSymbolOrErr; 316 else 317 return TargetSymbolOrErr.takeError(); 318 Addend = TargetAddress - TargetSymbol->getAddress(); 319 break; 320 } 321 case Delta32: 322 case Delta64: { 323 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 324 // parsePairRelocation handles the paired reloc, and returns the 325 // edge kind to be used (either Delta32/Delta64, or 326 // NegDelta32/NegDelta64, depending on the direction of the 327 // subtraction) along with the addend. 328 auto PairInfo = 329 parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress, 330 FixupContent, ++RelItr, RelEnd); 331 if (!PairInfo) 332 return PairInfo.takeError(); 333 std::tie(*Kind, TargetSymbol, Addend) = *PairInfo; 334 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 335 break; 336 } 337 default: 338 llvm_unreachable("Special relocation kind should not appear in " 339 "mach-o file"); 340 } 341 342 LLVM_DEBUG({ 343 Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 344 Addend); 345 printEdge(dbgs(), *BlockToFix, GE, 346 getMachOX86RelocationKindName(*Kind)); 347 dbgs() << "\n"; 348 }); 349 BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(), 350 *TargetSymbol, Addend); 351 } 352 } 353 return Error::success(); 354 } 355 }; 356 357 class MachO_x86_64_GOTAndStubsBuilder 358 : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> { 359 public: 360 static const uint8_t NullGOTEntryContent[8]; 361 static const uint8_t StubContent[6]; 362 363 MachO_x86_64_GOTAndStubsBuilder(LinkGraph &G) 364 : BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(G) {} 365 366 bool isGOTEdge(Edge &E) const { 367 return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad; 368 } 369 370 Symbol &createGOTEntry(Symbol &Target) { 371 auto &GOTEntryBlock = G.createContentBlock( 372 getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0); 373 GOTEntryBlock.addEdge(Pointer64, 0, Target, 0); 374 return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false); 375 } 376 377 void fixGOTEdge(Edge &E, Symbol &GOTEntry) { 378 assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) && 379 "Not a GOT edge?"); 380 // If this is a PCRel32GOT then change it to an ordinary PCRel32. If it is 381 // a PCRel32GOTLoad then leave it as-is for now. We will use the kind to 382 // check for GOT optimization opportunities in the 383 // optimizeMachO_x86_64_GOTAndStubs pass below. 384 if (E.getKind() == PCRel32GOT) 385 E.setKind(PCRel32); 386 387 E.setTarget(GOTEntry); 388 // Leave the edge addend as-is. 389 } 390 391 bool isExternalBranchEdge(Edge &E) { 392 return E.getKind() == Branch32 && !E.getTarget().isDefined(); 393 } 394 395 Symbol &createStub(Symbol &Target) { 396 auto &StubContentBlock = 397 G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0); 398 // Re-use GOT entries for stub targets. 399 auto &GOTEntrySymbol = getGOTEntrySymbol(Target); 400 StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, 0); 401 return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false); 402 } 403 404 void fixExternalBranchEdge(Edge &E, Symbol &Stub) { 405 assert(E.getKind() == Branch32 && "Not a Branch32 edge?"); 406 assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?"); 407 408 // Set the edge kind to Branch32ToStub. We will use this to check for stub 409 // optimization opportunities in the optimizeMachO_x86_64_GOTAndStubs pass 410 // below. 411 E.setKind(Branch32ToStub); 412 E.setTarget(Stub); 413 } 414 415 private: 416 Section &getGOTSection() { 417 if (!GOTSection) 418 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ); 419 return *GOTSection; 420 } 421 422 Section &getStubsSection() { 423 if (!StubsSection) { 424 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>( 425 sys::Memory::MF_READ | sys::Memory::MF_EXEC); 426 StubsSection = &G.createSection("$__STUBS", StubsProt); 427 } 428 return *StubsSection; 429 } 430 431 StringRef getGOTEntryBlockContent() { 432 return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent), 433 sizeof(NullGOTEntryContent)); 434 } 435 436 StringRef getStubBlockContent() { 437 return StringRef(reinterpret_cast<const char *>(StubContent), 438 sizeof(StubContent)); 439 } 440 441 Section *GOTSection = nullptr; 442 Section *StubsSection = nullptr; 443 }; 444 445 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = { 446 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 447 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = { 448 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00}; 449 } // namespace 450 451 static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) { 452 LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n"); 453 454 for (auto *B : G.blocks()) 455 for (auto &E : B->edges()) 456 if (E.getKind() == PCRel32GOTLoad) { 457 assert(E.getOffset() >= 3 && "GOT edge occurs too early in block"); 458 459 // Switch the edge kind to PCRel32: Whether we change the edge target 460 // or not this will be the desired kind. 461 E.setKind(PCRel32); 462 463 // Optimize GOT references. 464 auto &GOTBlock = E.getTarget().getBlock(); 465 assert(GOTBlock.getSize() == G.getPointerSize() && 466 "GOT entry block should be pointer sized"); 467 assert(GOTBlock.edges_size() == 1 && 468 "GOT entry should only have one outgoing edge"); 469 470 auto &GOTTarget = GOTBlock.edges().begin()->getTarget(); 471 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset(); 472 JITTargetAddress TargetAddr = GOTTarget.getAddress(); 473 474 // Check that this is a recognized MOV instruction. 475 // FIXME: Can we assume this? 476 constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b}; 477 if (strncmp(B->getContent().data() + E.getOffset() - 3, 478 reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0) 479 continue; 480 481 int64_t Displacement = TargetAddr - EdgeAddr + 4; 482 if (Displacement >= std::numeric_limits<int32_t>::min() && 483 Displacement <= std::numeric_limits<int32_t>::max()) { 484 E.setTarget(GOTTarget); 485 auto *BlockData = reinterpret_cast<uint8_t *>( 486 const_cast<char *>(B->getContent().data())); 487 BlockData[E.getOffset() - 2] = 0x8d; 488 LLVM_DEBUG({ 489 dbgs() << " Replaced GOT load wih LEA:\n "; 490 printEdge(dbgs(), *B, E, 491 getMachOX86RelocationKindName(E.getKind())); 492 dbgs() << "\n"; 493 }); 494 } 495 } else if (E.getKind() == Branch32ToStub) { 496 497 // Switch the edge kind to PCRel32: Whether we change the edge target 498 // or not this will be the desired kind. 499 E.setKind(Branch32); 500 501 auto &StubBlock = E.getTarget().getBlock(); 502 assert(StubBlock.getSize() == 503 sizeof(MachO_x86_64_GOTAndStubsBuilder::StubContent) && 504 "Stub block should be stub sized"); 505 assert(StubBlock.edges_size() == 1 && 506 "Stub block should only have one outgoing edge"); 507 508 auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock(); 509 assert(GOTBlock.getSize() == G.getPointerSize() && 510 "GOT block should be pointer sized"); 511 assert(GOTBlock.edges_size() == 1 && 512 "GOT block should only have one outgoing edge"); 513 514 auto &GOTTarget = GOTBlock.edges().begin()->getTarget(); 515 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset(); 516 JITTargetAddress TargetAddr = GOTTarget.getAddress(); 517 518 int64_t Displacement = TargetAddr - EdgeAddr + 4; 519 if (Displacement >= std::numeric_limits<int32_t>::min() && 520 Displacement <= std::numeric_limits<int32_t>::max()) { 521 E.setTarget(GOTTarget); 522 LLVM_DEBUG({ 523 dbgs() << " Replaced stub branch with direct branch:\n "; 524 printEdge(dbgs(), *B, E, 525 getMachOX86RelocationKindName(E.getKind())); 526 dbgs() << "\n"; 527 }); 528 } 529 } 530 531 return Error::success(); 532 } 533 534 namespace llvm { 535 namespace jitlink { 536 537 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { 538 friend class JITLinker<MachOJITLinker_x86_64>; 539 540 public: 541 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 542 PassConfiguration PassConfig) 543 : JITLinker(std::move(Ctx), std::move(PassConfig)) {} 544 545 private: 546 StringRef getEdgeKindName(Edge::Kind R) const override { 547 return getMachOX86RelocationKindName(R); 548 } 549 550 Expected<std::unique_ptr<LinkGraph>> 551 buildGraph(MemoryBufferRef ObjBuffer) override { 552 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer); 553 if (!MachOObj) 554 return MachOObj.takeError(); 555 return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph(); 556 } 557 558 static Error targetOutOfRangeError(const Block &B, const Edge &E) { 559 std::string ErrMsg; 560 { 561 raw_string_ostream ErrStream(ErrMsg); 562 ErrStream << "Relocation target out of range: "; 563 printEdge(ErrStream, B, E, getMachOX86RelocationKindName(E.getKind())); 564 ErrStream << "\n"; 565 } 566 return make_error<JITLinkError>(std::move(ErrMsg)); 567 } 568 569 Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const { 570 571 using namespace support; 572 573 char *FixupPtr = BlockWorkingMem + E.getOffset(); 574 JITTargetAddress FixupAddress = B.getAddress() + E.getOffset(); 575 576 switch (E.getKind()) { 577 case Branch32: 578 case PCRel32: 579 case PCRel32Anon: { 580 int64_t Value = 581 E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend(); 582 if (Value < std::numeric_limits<int32_t>::min() || 583 Value > std::numeric_limits<int32_t>::max()) 584 return targetOutOfRangeError(B, E); 585 *(little32_t *)FixupPtr = Value; 586 break; 587 } 588 case Pointer64: 589 case Pointer64Anon: { 590 uint64_t Value = E.getTarget().getAddress() + E.getAddend(); 591 *(ulittle64_t *)FixupPtr = Value; 592 break; 593 } 594 case PCRel32Minus1: 595 case PCRel32Minus2: 596 case PCRel32Minus4: { 597 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1)); 598 int64_t Value = 599 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend(); 600 if (Value < std::numeric_limits<int32_t>::min() || 601 Value > std::numeric_limits<int32_t>::max()) 602 return targetOutOfRangeError(B, E); 603 *(little32_t *)FixupPtr = Value; 604 break; 605 } 606 case PCRel32Minus1Anon: 607 case PCRel32Minus2Anon: 608 case PCRel32Minus4Anon: { 609 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon)); 610 int64_t Value = 611 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend(); 612 if (Value < std::numeric_limits<int32_t>::min() || 613 Value > std::numeric_limits<int32_t>::max()) 614 return targetOutOfRangeError(B, E); 615 *(little32_t *)FixupPtr = Value; 616 break; 617 } 618 case Delta32: 619 case Delta64: 620 case NegDelta32: 621 case NegDelta64: { 622 int64_t Value; 623 if (E.getKind() == Delta32 || E.getKind() == Delta64) 624 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 625 else 626 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); 627 628 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) { 629 if (Value < std::numeric_limits<int32_t>::min() || 630 Value > std::numeric_limits<int32_t>::max()) 631 return targetOutOfRangeError(B, E); 632 *(little32_t *)FixupPtr = Value; 633 } else 634 *(little64_t *)FixupPtr = Value; 635 break; 636 } 637 case Pointer32: { 638 uint64_t Value = E.getTarget().getAddress() + E.getAddend(); 639 if (Value > std::numeric_limits<uint32_t>::max()) 640 return targetOutOfRangeError(B, E); 641 *(ulittle32_t *)FixupPtr = Value; 642 break; 643 } 644 default: 645 llvm_unreachable("Unrecognized edge kind"); 646 } 647 648 return Error::success(); 649 } 650 651 uint64_t NullValue = 0; 652 }; 653 654 void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) { 655 PassConfiguration Config; 656 Triple TT("x86_64-apple-macosx"); 657 658 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 659 // Add eh-frame passses. 660 Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame")); 661 Config.PrePrunePasses.push_back( 662 EHFrameEdgeFixer("__eh_frame", NegDelta32, Delta64, Delta64)); 663 664 // Add a mark-live pass. 665 if (auto MarkLive = Ctx->getMarkLivePass(TT)) 666 Config.PrePrunePasses.push_back(std::move(MarkLive)); 667 else 668 Config.PrePrunePasses.push_back(markAllSymbolsLive); 669 670 // Add an in-place GOT/Stubs pass. 671 Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error { 672 MachO_x86_64_GOTAndStubsBuilder(G).run(); 673 return Error::success(); 674 }); 675 676 // Add GOT/Stubs optimizer pass. 677 Config.PostAllocationPasses.push_back(optimizeMachO_x86_64_GOTAndStubs); 678 } 679 680 if (auto Err = Ctx->modifyPassConfig(TT, Config)) 681 return Ctx->notifyFailed(std::move(Err)); 682 683 // Construct a JITLinker and run the link function. 684 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config)); 685 } 686 687 StringRef getMachOX86RelocationKindName(Edge::Kind R) { 688 switch (R) { 689 case Branch32: 690 return "Branch32"; 691 case Branch32ToStub: 692 return "Branch32ToStub"; 693 case Pointer32: 694 return "Pointer32"; 695 case Pointer64: 696 return "Pointer64"; 697 case Pointer64Anon: 698 return "Pointer64Anon"; 699 case PCRel32: 700 return "PCRel32"; 701 case PCRel32Minus1: 702 return "PCRel32Minus1"; 703 case PCRel32Minus2: 704 return "PCRel32Minus2"; 705 case PCRel32Minus4: 706 return "PCRel32Minus4"; 707 case PCRel32Anon: 708 return "PCRel32Anon"; 709 case PCRel32Minus1Anon: 710 return "PCRel32Minus1Anon"; 711 case PCRel32Minus2Anon: 712 return "PCRel32Minus2Anon"; 713 case PCRel32Minus4Anon: 714 return "PCRel32Minus4Anon"; 715 case PCRel32GOTLoad: 716 return "PCRel32GOTLoad"; 717 case PCRel32GOT: 718 return "PCRel32GOT"; 719 case PCRel32TLV: 720 return "PCRel32TLV"; 721 case Delta32: 722 return "Delta32"; 723 case Delta64: 724 return "Delta64"; 725 case NegDelta32: 726 return "NegDelta32"; 727 case NegDelta64: 728 return "NegDelta64"; 729 default: 730 return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); 731 } 732 } 733 734 } // end namespace jitlink 735 } // end namespace llvm 736