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