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