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 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 15 16 #include "MachOLinkGraphBuilder.h" 17 #include "PerGraphGOTAndPLTStubsBuilder.h" 18 19 #define DEBUG_TYPE "jitlink" 20 21 using namespace llvm; 22 using namespace llvm::jitlink; 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 x86_64::getEdgeKindName) {} 31 32 private: 33 enum MachONormalizedRelocationType : unsigned { 34 MachOBranch32, 35 MachOPointer32, 36 MachOPointer64, 37 MachOPointer64Anon, 38 MachOPCRel32, 39 MachOPCRel32Minus1, 40 MachOPCRel32Minus2, 41 MachOPCRel32Minus4, 42 MachOPCRel32Anon, 43 MachOPCRel32Minus1Anon, 44 MachOPCRel32Minus2Anon, 45 MachOPCRel32Minus4Anon, 46 MachOPCRel32GOTLoad, 47 MachOPCRel32GOT, 48 MachOPCRel32TLV, 49 MachOSubtractor32, 50 MachOSubtractor64, 51 }; 52 53 static Expected<MachONormalizedRelocationType> 54 getRelocKind(const MachO::relocation_info &RI) { 55 switch (RI.r_type) { 56 case MachO::X86_64_RELOC_UNSIGNED: 57 if (!RI.r_pcrel) { 58 if (RI.r_length == 3) 59 return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; 60 else if (RI.r_extern && RI.r_length == 2) 61 return MachOPointer32; 62 } 63 break; 64 case MachO::X86_64_RELOC_SIGNED: 65 if (RI.r_pcrel && RI.r_length == 2) 66 return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon; 67 break; 68 case MachO::X86_64_RELOC_BRANCH: 69 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 70 return MachOBranch32; 71 break; 72 case MachO::X86_64_RELOC_GOT_LOAD: 73 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 74 return MachOPCRel32GOTLoad; 75 break; 76 case MachO::X86_64_RELOC_GOT: 77 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 78 return MachOPCRel32GOT; 79 break; 80 case MachO::X86_64_RELOC_SUBTRACTOR: 81 if (!RI.r_pcrel && RI.r_extern) { 82 if (RI.r_length == 2) 83 return MachOSubtractor32; 84 else if (RI.r_length == 3) 85 return MachOSubtractor64; 86 } 87 break; 88 case MachO::X86_64_RELOC_SIGNED_1: 89 if (RI.r_pcrel && RI.r_length == 2) 90 return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon; 91 break; 92 case MachO::X86_64_RELOC_SIGNED_2: 93 if (RI.r_pcrel && RI.r_length == 2) 94 return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon; 95 break; 96 case MachO::X86_64_RELOC_SIGNED_4: 97 if (RI.r_pcrel && RI.r_length == 2) 98 return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon; 99 break; 100 case MachO::X86_64_RELOC_TLV: 101 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 102 return MachOPCRel32TLV; 103 break; 104 } 105 106 return make_error<JITLinkError>( 107 "Unsupported x86-64 relocation: address=" + 108 formatv("{0:x8}", RI.r_address) + 109 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) + 110 ", kind=" + formatv("{0:x1}", RI.r_type) + 111 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") + 112 ", extern=" + (RI.r_extern ? "true" : "false") + 113 ", length=" + formatv("{0:d}", RI.r_length)); 114 } 115 116 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; 117 118 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, 119 // returns the edge kind and addend to be used. 120 Expected<PairRelocInfo> parsePairRelocation( 121 Block &BlockToFix, MachONormalizedRelocationType SubtractorKind, 122 const MachO::relocation_info &SubRI, JITTargetAddress FixupAddress, 123 const char *FixupContent, object::relocation_iterator &UnsignedRelItr, 124 object::relocation_iterator &RelEnd) { 125 using namespace support; 126 127 assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) || 128 (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) && 129 "Subtractor kind should match length"); 130 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); 131 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); 132 133 if (UnsignedRelItr == RelEnd) 134 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired " 135 "UNSIGNED relocation"); 136 137 auto UnsignedRI = getRelocationInfo(UnsignedRelItr); 138 139 if (SubRI.r_address != UnsignedRI.r_address) 140 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED " 141 "point to different addresses"); 142 143 if (SubRI.r_length != UnsignedRI.r_length) 144 return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired " 145 "UNSIGNED reloc must match"); 146 147 Symbol *FromSymbol; 148 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) 149 FromSymbol = FromSymbolOrErr->GraphSymbol; 150 else 151 return FromSymbolOrErr.takeError(); 152 153 // Read the current fixup value. 154 uint64_t FixupValue = 0; 155 if (SubRI.r_length == 3) 156 FixupValue = *(const little64_t *)FixupContent; 157 else 158 FixupValue = *(const little32_t *)FixupContent; 159 160 // Find 'ToSymbol' using symbol number or address, depending on whether the 161 // paired UNSIGNED relocation is extern. 162 Symbol *ToSymbol = nullptr; 163 if (UnsignedRI.r_extern) { 164 // Find target symbol by symbol index. 165 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) 166 ToSymbol = ToSymbolOrErr->GraphSymbol; 167 else 168 return ToSymbolOrErr.takeError(); 169 } else { 170 auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1); 171 if (!ToSymbolSec) 172 return ToSymbolSec.takeError(); 173 ToSymbol = getSymbolByAddress(ToSymbolSec->Address); 174 assert(ToSymbol && "No symbol for section"); 175 FixupValue -= ToSymbol->getAddress(); 176 } 177 178 Edge::Kind DeltaKind; 179 Symbol *TargetSymbol; 180 uint64_t Addend; 181 if (&BlockToFix == &FromSymbol->getAddressable()) { 182 TargetSymbol = ToSymbol; 183 DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32; 184 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 185 // FIXME: handle extern 'from'. 186 } else if (&BlockToFix == &ToSymbol->getAddressable()) { 187 TargetSymbol = FromSymbol; 188 DeltaKind = 189 (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32; 190 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 191 } else { 192 // BlockToFix was neither FromSymbol nor ToSymbol. 193 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 194 "either 'A' or 'B' (or a symbol in one " 195 "of their alt-entry chains)"); 196 } 197 198 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 199 } 200 201 Error addRelocations() override { 202 using namespace support; 203 auto &Obj = getObject(); 204 205 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 206 207 for (auto &S : Obj.sections()) { 208 209 JITTargetAddress SectionAddress = S.getAddress(); 210 211 // Skip relocations virtual sections. 212 if (S.isVirtual()) { 213 if (S.relocation_begin() != S.relocation_end()) 214 return make_error<JITLinkError>("Virtual section contains " 215 "relocations"); 216 continue; 217 } 218 219 // Skip relocations for debug symbols. 220 { 221 auto &NSec = 222 getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 223 if (!NSec.GraphSection) { 224 LLVM_DEBUG({ 225 dbgs() << " Skipping relocations for MachO section " 226 << NSec.SegName << "/" << NSec.SectName 227 << " which has no associated graph section\n"; 228 }); 229 continue; 230 } 231 } 232 233 // Add relocations for section. 234 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 235 RelItr != RelEnd; ++RelItr) { 236 237 MachO::relocation_info RI = getRelocationInfo(RelItr); 238 239 // Find the address of the value to fix up. 240 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address; 241 242 LLVM_DEBUG({ 243 auto &NSec = 244 getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 245 dbgs() << " " << NSec.SectName << " + " 246 << formatv("{0:x8}", RI.r_address) << ":\n"; 247 }); 248 249 // Find the block that the fixup points to. 250 Block *BlockToFix = nullptr; 251 { 252 auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress); 253 if (!SymbolToFixOrErr) 254 return SymbolToFixOrErr.takeError(); 255 BlockToFix = &SymbolToFixOrErr->getBlock(); 256 } 257 258 if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) > 259 BlockToFix->getAddress() + BlockToFix->getContent().size()) 260 return make_error<JITLinkError>( 261 "Relocation extends past end of fixup block"); 262 263 // Get a pointer to the fixup content. 264 const char *FixupContent = BlockToFix->getContent().data() + 265 (FixupAddress - BlockToFix->getAddress()); 266 267 size_t FixupOffset = FixupAddress - BlockToFix->getAddress(); 268 269 // The target symbol and addend will be populated by the switch below. 270 Symbol *TargetSymbol = nullptr; 271 uint64_t Addend = 0; 272 273 // Sanity check the relocation kind. 274 auto MachORelocKind = getRelocKind(RI); 275 if (!MachORelocKind) 276 return MachORelocKind.takeError(); 277 278 Edge::Kind Kind = Edge::Invalid; 279 280 switch (*MachORelocKind) { 281 case MachOBranch32: 282 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 283 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 284 else 285 return TargetSymbolOrErr.takeError(); 286 Addend = *(const little32_t *)FixupContent; 287 Kind = x86_64::BranchPCRel32; 288 break; 289 case MachOPCRel32: 290 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 291 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 292 else 293 return TargetSymbolOrErr.takeError(); 294 Addend = *(const little32_t *)FixupContent - 4; 295 Kind = x86_64::Delta32; 296 break; 297 case MachOPCRel32GOTLoad: 298 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 299 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 300 else 301 return TargetSymbolOrErr.takeError(); 302 Addend = *(const little32_t *)FixupContent; 303 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable; 304 if (FixupOffset < 3) 305 return make_error<JITLinkError>("GOTLD at invalid offset " + 306 formatv("{0}", FixupOffset)); 307 break; 308 case MachOPCRel32GOT: 309 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 310 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 311 else 312 return TargetSymbolOrErr.takeError(); 313 Addend = *(const little32_t *)FixupContent - 4; 314 Kind = x86_64::RequestGOTAndTransformToDelta32; 315 break; 316 case MachOPointer32: 317 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 318 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 319 else 320 return TargetSymbolOrErr.takeError(); 321 Addend = *(const ulittle32_t *)FixupContent; 322 Kind = x86_64::Pointer32; 323 break; 324 case MachOPointer64: 325 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 326 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 327 else 328 return TargetSymbolOrErr.takeError(); 329 Addend = *(const ulittle64_t *)FixupContent; 330 Kind = x86_64::Pointer64; 331 break; 332 case MachOPointer64Anon: { 333 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent; 334 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 335 TargetSymbol = &*TargetSymbolOrErr; 336 else 337 return TargetSymbolOrErr.takeError(); 338 Addend = TargetAddress - TargetSymbol->getAddress(); 339 Kind = x86_64::Pointer64; 340 break; 341 } 342 case MachOPCRel32Minus1: 343 case MachOPCRel32Minus2: 344 case MachOPCRel32Minus4: 345 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 346 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 347 else 348 return TargetSymbolOrErr.takeError(); 349 Addend = *(const little32_t *)FixupContent - 4; 350 // - 351 // (1 << (*MachORelocKind - MachOPCRel32Minus1)); 352 Kind = x86_64::Delta32; 353 break; 354 case MachOPCRel32Anon: { 355 JITTargetAddress TargetAddress = 356 FixupAddress + 4 + *(const little32_t *)FixupContent; 357 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 358 TargetSymbol = &*TargetSymbolOrErr; 359 else 360 return TargetSymbolOrErr.takeError(); 361 Addend = TargetAddress - TargetSymbol->getAddress() - 4; 362 Kind = x86_64::Delta32; 363 break; 364 } 365 case MachOPCRel32Minus1Anon: 366 case MachOPCRel32Minus2Anon: 367 case MachOPCRel32Minus4Anon: { 368 JITTargetAddress Delta = 369 4 + static_cast<JITTargetAddress>( 370 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon)); 371 JITTargetAddress TargetAddress = 372 FixupAddress + Delta + *(const little32_t *)FixupContent; 373 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) 374 TargetSymbol = &*TargetSymbolOrErr; 375 else 376 return TargetSymbolOrErr.takeError(); 377 Addend = TargetAddress - TargetSymbol->getAddress() - Delta; 378 Kind = x86_64::Delta32; 379 break; 380 } 381 case MachOSubtractor32: 382 case MachOSubtractor64: { 383 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 384 // parsePairRelocation handles the paired reloc, and returns the 385 // edge kind to be used (either Delta32/Delta64, or 386 // NegDelta32/NegDelta64, depending on the direction of the 387 // subtraction) along with the addend. 388 auto PairInfo = 389 parsePairRelocation(*BlockToFix, *MachORelocKind, RI, 390 FixupAddress, FixupContent, ++RelItr, RelEnd); 391 if (!PairInfo) 392 return PairInfo.takeError(); 393 std::tie(Kind, TargetSymbol, Addend) = *PairInfo; 394 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 395 break; 396 } 397 case MachOPCRel32TLV: 398 return make_error<JITLinkError>( 399 "MachO TLV relocations not yet supported"); 400 } 401 402 LLVM_DEBUG({ 403 dbgs() << " "; 404 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 405 Addend); 406 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); 407 dbgs() << "\n"; 408 }); 409 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), 410 *TargetSymbol, Addend); 411 } 412 } 413 return Error::success(); 414 } 415 }; 416 417 class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64 418 : public PerGraphGOTAndPLTStubsBuilder< 419 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> { 420 public: 421 static const uint8_t NullGOTEntryContent[8]; 422 static const uint8_t StubContent[6]; 423 424 using PerGraphGOTAndPLTStubsBuilder< 425 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>:: 426 PerGraphGOTAndPLTStubsBuilder; 427 428 bool isGOTEdgeToFix(Edge &E) const { 429 return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 || 430 E.getKind() == 431 x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable; 432 } 433 434 Symbol &createGOTEntry(Symbol &Target) { 435 auto &GOTEntryBlock = G.createContentBlock( 436 getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0); 437 GOTEntryBlock.addEdge(x86_64::Pointer64, 0, Target, 0); 438 return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false); 439 } 440 441 void fixGOTEdge(Edge &E, Symbol &GOTEntry) { 442 // Fix the edge kind. 443 switch (E.getKind()) { 444 case x86_64::RequestGOTAndTransformToDelta32: 445 E.setKind(x86_64::Delta32); 446 break; 447 case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable: 448 E.setKind(x86_64::PCRel32GOTLoadRelaxable); 449 break; 450 default: 451 llvm_unreachable("Not a GOT transform edge"); 452 } 453 // Fix the target, leave the addend as-is. 454 E.setTarget(GOTEntry); 455 } 456 457 bool isExternalBranchEdge(Edge &E) { 458 return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal(); 459 } 460 461 Symbol &createPLTStub(Symbol &Target) { 462 auto &StubContentBlock = 463 G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0); 464 // Re-use GOT entries for stub targets. 465 auto &GOTEntrySymbol = getGOTEntry(Target); 466 StubContentBlock.addEdge(x86_64::Delta32, 2, GOTEntrySymbol, -4); 467 return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false); 468 } 469 470 void fixPLTEdge(Edge &E, Symbol &Stub) { 471 assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?"); 472 assert(E.getAddend() == 0 && 473 "BranchPCRel32 edge has unexpected addend value"); 474 475 // Set the edge kind to BranchPCRel32ToPtrJumpStubRelaxable. We will use 476 // this to check for stub optimization opportunities in the 477 // optimizeMachO_x86_64_GOTAndStubs pass below. 478 E.setKind(x86_64::BranchPCRel32ToPtrJumpStubRelaxable); 479 E.setTarget(Stub); 480 } 481 482 private: 483 Section &getGOTSection() { 484 if (!GOTSection) 485 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ); 486 return *GOTSection; 487 } 488 489 Section &getStubsSection() { 490 if (!StubsSection) { 491 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>( 492 sys::Memory::MF_READ | sys::Memory::MF_EXEC); 493 StubsSection = &G.createSection("$__STUBS", StubsProt); 494 } 495 return *StubsSection; 496 } 497 498 StringRef getGOTEntryBlockContent() { 499 return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent), 500 sizeof(NullGOTEntryContent)); 501 } 502 503 StringRef getStubBlockContent() { 504 return StringRef(reinterpret_cast<const char *>(StubContent), 505 sizeof(StubContent)); 506 } 507 508 Section *GOTSection = nullptr; 509 Section *StubsSection = nullptr; 510 }; 511 512 const uint8_t 513 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::NullGOTEntryContent[8] = { 514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 515 const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent[6] = { 516 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00}; 517 } // namespace 518 519 static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) { 520 LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n"); 521 522 for (auto *B : G.blocks()) 523 for (auto &E : B->edges()) 524 if (E.getKind() == x86_64::PCRel32GOTLoadRelaxable) { 525 assert(E.getOffset() >= 3 && "GOT edge occurs too early in block"); 526 527 // Optimize GOT references. 528 auto &GOTBlock = E.getTarget().getBlock(); 529 assert(GOTBlock.getSize() == G.getPointerSize() && 530 "GOT entry block should be pointer sized"); 531 assert(GOTBlock.edges_size() == 1 && 532 "GOT entry should only have one outgoing edge"); 533 534 auto &GOTTarget = GOTBlock.edges().begin()->getTarget(); 535 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset(); 536 JITTargetAddress TargetAddr = GOTTarget.getAddress(); 537 538 // Check that this is a recognized MOV instruction. 539 // FIXME: Can we assume this? 540 constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b}; 541 if (strncmp(B->getContent().data() + E.getOffset() - 3, 542 reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0) 543 continue; 544 545 int64_t Displacement = TargetAddr - EdgeAddr + 4; 546 if (Displacement >= std::numeric_limits<int32_t>::min() && 547 Displacement <= std::numeric_limits<int32_t>::max()) { 548 E.setTarget(GOTTarget); 549 E.setKind(x86_64::Delta32); 550 E.setAddend(E.getAddend() - 4); 551 auto *BlockData = reinterpret_cast<uint8_t *>( 552 const_cast<char *>(B->getContent().data())); 553 BlockData[E.getOffset() - 2] = 0x8d; 554 LLVM_DEBUG({ 555 dbgs() << " Replaced GOT load wih LEA:\n "; 556 printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind())); 557 dbgs() << "\n"; 558 }); 559 } 560 } else if (E.getKind() == x86_64::BranchPCRel32ToPtrJumpStubRelaxable) { 561 auto &StubBlock = E.getTarget().getBlock(); 562 assert( 563 StubBlock.getSize() == 564 sizeof( 565 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent) && 566 "Stub block should be stub sized"); 567 assert(StubBlock.edges_size() == 1 && 568 "Stub block should only have one outgoing edge"); 569 570 auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock(); 571 assert(GOTBlock.getSize() == G.getPointerSize() && 572 "GOT block should be pointer sized"); 573 assert(GOTBlock.edges_size() == 1 && 574 "GOT block should only have one outgoing edge"); 575 576 auto &GOTTarget = GOTBlock.edges().begin()->getTarget(); 577 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset(); 578 JITTargetAddress TargetAddr = GOTTarget.getAddress(); 579 580 int64_t Displacement = TargetAddr - EdgeAddr + 4; 581 if (Displacement >= std::numeric_limits<int32_t>::min() && 582 Displacement <= std::numeric_limits<int32_t>::max()) { 583 E.setKind(x86_64::BranchPCRel32); 584 E.setTarget(GOTTarget); 585 LLVM_DEBUG({ 586 dbgs() << " Replaced stub branch with direct branch:\n "; 587 printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind())); 588 dbgs() << "\n"; 589 }); 590 } 591 } 592 593 return Error::success(); 594 } 595 596 namespace llvm { 597 namespace jitlink { 598 599 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { 600 friend class JITLinker<MachOJITLinker_x86_64>; 601 602 public: 603 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 604 std::unique_ptr<LinkGraph> G, 605 PassConfiguration PassConfig) 606 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 607 608 private: 609 Error applyFixup(LinkGraph &G, Block &B, const Edge &E, 610 char *BlockWorkingMem) const { 611 return x86_64::applyFixup(G, B, E, BlockWorkingMem); 612 } 613 }; 614 615 Expected<std::unique_ptr<LinkGraph>> 616 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) { 617 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); 618 if (!MachOObj) 619 return MachOObj.takeError(); 620 return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph(); 621 } 622 623 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, 624 std::unique_ptr<JITLinkContext> Ctx) { 625 626 PassConfiguration Config; 627 628 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 629 // Add eh-frame passses. 630 Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame")); 631 Config.PrePrunePasses.push_back( 632 EHFrameEdgeFixer("__eh_frame", G->getPointerSize(), x86_64::Delta64, 633 x86_64::Delta32, x86_64::NegDelta32)); 634 635 // Add a mark-live pass. 636 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 637 Config.PrePrunePasses.push_back(std::move(MarkLive)); 638 else 639 Config.PrePrunePasses.push_back(markAllSymbolsLive); 640 641 // Add an in-place GOT/Stubs pass. 642 Config.PostPrunePasses.push_back( 643 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass); 644 645 // Add GOT/Stubs optimizer pass. 646 Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs); 647 } 648 649 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 650 return Ctx->notifyFailed(std::move(Err)); 651 652 // Construct a JITLinker and run the link function. 653 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 654 } 655 656 } // end namespace jitlink 657 } // end namespace llvm 658