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/DWARFRecordSectionSplitter.h" 15 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 16 17 #include "DefineExternalSectionStartAndEndSymbols.h" 18 #include "MachOLinkGraphBuilder.h" 19 20 #define DEBUG_TYPE "jitlink" 21 22 using namespace llvm; 23 using namespace llvm::jitlink; 24 25 namespace { 26 27 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder { 28 public: 29 MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj, 30 std::shared_ptr<orc::SymbolStringPool> SSP, 31 SubtargetFeatures Features) 32 : MachOLinkGraphBuilder(Obj, std::move(SSP), 33 Triple("x86_64-apple-darwin"), 34 std::move(Features), x86_64::getEdgeKindName) {} 35 36 private: 37 enum MachONormalizedRelocationType : unsigned { 38 MachOBranch32, 39 MachOPointer32, 40 MachOPointer64, 41 MachOPointer64Anon, 42 MachOPCRel32, 43 MachOPCRel32Minus1, 44 MachOPCRel32Minus2, 45 MachOPCRel32Minus4, 46 MachOPCRel32Anon, 47 MachOPCRel32Minus1Anon, 48 MachOPCRel32Minus2Anon, 49 MachOPCRel32Minus4Anon, 50 MachOPCRel32GOTLoad, 51 MachOPCRel32GOT, 52 MachOPCRel32TLV, 53 MachOSubtractor32, 54 MachOSubtractor64, 55 }; 56 57 static Expected<MachONormalizedRelocationType> 58 getRelocKind(const MachO::relocation_info &RI) { 59 switch (RI.r_type) { 60 case MachO::X86_64_RELOC_UNSIGNED: 61 if (!RI.r_pcrel) { 62 if (RI.r_length == 3) 63 return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; 64 else if (RI.r_extern && RI.r_length == 2) 65 return MachOPointer32; 66 } 67 break; 68 case MachO::X86_64_RELOC_SIGNED: 69 if (RI.r_pcrel && RI.r_length == 2) 70 return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon; 71 break; 72 case MachO::X86_64_RELOC_BRANCH: 73 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 74 return MachOBranch32; 75 break; 76 case MachO::X86_64_RELOC_GOT_LOAD: 77 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 78 return MachOPCRel32GOTLoad; 79 break; 80 case MachO::X86_64_RELOC_GOT: 81 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 82 return MachOPCRel32GOT; 83 break; 84 case MachO::X86_64_RELOC_SUBTRACTOR: 85 if (!RI.r_pcrel && RI.r_extern) { 86 if (RI.r_length == 2) 87 return MachOSubtractor32; 88 else if (RI.r_length == 3) 89 return MachOSubtractor64; 90 } 91 break; 92 case MachO::X86_64_RELOC_SIGNED_1: 93 if (RI.r_pcrel && RI.r_length == 2) 94 return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon; 95 break; 96 case MachO::X86_64_RELOC_SIGNED_2: 97 if (RI.r_pcrel && RI.r_length == 2) 98 return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon; 99 break; 100 case MachO::X86_64_RELOC_SIGNED_4: 101 if (RI.r_pcrel && RI.r_length == 2) 102 return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon; 103 break; 104 case MachO::X86_64_RELOC_TLV: 105 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 106 return MachOPCRel32TLV; 107 break; 108 } 109 110 return make_error<JITLinkError>( 111 "Unsupported x86-64 relocation: address=" + 112 formatv("{0:x8}", RI.r_address) + 113 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) + 114 ", kind=" + formatv("{0:x1}", RI.r_type) + 115 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") + 116 ", extern=" + (RI.r_extern ? "true" : "false") + 117 ", length=" + formatv("{0:d}", RI.r_length)); 118 } 119 120 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; 121 122 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, 123 // returns the edge kind and addend to be used. 124 Expected<PairRelocInfo> parsePairRelocation( 125 Block &BlockToFix, MachONormalizedRelocationType SubtractorKind, 126 const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress, 127 const char *FixupContent, object::relocation_iterator &UnsignedRelItr, 128 object::relocation_iterator &RelEnd) { 129 using namespace support; 130 131 assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) || 132 (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) && 133 "Subtractor kind should match length"); 134 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); 135 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); 136 137 if (UnsignedRelItr == RelEnd) 138 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired " 139 "UNSIGNED relocation"); 140 141 auto UnsignedRI = getRelocationInfo(UnsignedRelItr); 142 143 if (SubRI.r_address != UnsignedRI.r_address) 144 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED " 145 "point to different addresses"); 146 147 if (SubRI.r_length != UnsignedRI.r_length) 148 return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired " 149 "UNSIGNED reloc must match"); 150 151 Symbol *FromSymbol; 152 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) 153 FromSymbol = FromSymbolOrErr->GraphSymbol; 154 else 155 return FromSymbolOrErr.takeError(); 156 157 // Read the current fixup value. 158 uint64_t FixupValue = 0; 159 if (SubRI.r_length == 3) 160 FixupValue = *(const little64_t *)FixupContent; 161 else 162 FixupValue = *(const little32_t *)FixupContent; 163 164 // Find 'ToSymbol' using symbol number or address, depending on whether the 165 // paired UNSIGNED relocation is extern. 166 Symbol *ToSymbol = nullptr; 167 if (UnsignedRI.r_extern) { 168 // Find target symbol by symbol index. 169 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) 170 ToSymbol = ToSymbolOrErr->GraphSymbol; 171 else 172 return ToSymbolOrErr.takeError(); 173 } else { 174 auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1); 175 if (!ToSymbolSec) 176 return ToSymbolSec.takeError(); 177 ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address); 178 assert(ToSymbol && "No symbol for section"); 179 FixupValue -= ToSymbol->getAddress().getValue(); 180 } 181 182 Edge::Kind DeltaKind; 183 Symbol *TargetSymbol; 184 uint64_t Addend; 185 186 bool FixingFromSymbol = true; 187 if (&BlockToFix == &FromSymbol->getAddressable()) { 188 if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) { 189 // From and To are symbols in the same block. Decide direction by offset 190 // instead. 191 if (ToSymbol->getAddress() > FixupAddress) 192 FixingFromSymbol = true; 193 else if (FromSymbol->getAddress() > FixupAddress) 194 FixingFromSymbol = false; 195 else 196 FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress(); 197 } else 198 FixingFromSymbol = true; 199 } else { 200 if (&BlockToFix == &ToSymbol->getAddressable()) 201 FixingFromSymbol = false; 202 else { 203 // BlockToFix was neither FromSymbol nor ToSymbol. 204 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 205 "either 'A' or 'B' (or a symbol in one " 206 "of their alt-entry groups)"); 207 } 208 } 209 210 if (FixingFromSymbol) { 211 TargetSymbol = ToSymbol; 212 DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32; 213 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 214 // FIXME: handle extern 'from'. 215 } else { 216 TargetSymbol = FromSymbol; 217 DeltaKind = 218 (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32; 219 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 220 } 221 222 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 223 } 224 225 Error addRelocations() override { 226 using namespace support; 227 auto &Obj = getObject(); 228 229 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 230 231 for (const auto &S : Obj.sections()) { 232 233 orc::ExecutorAddr SectionAddress(S.getAddress()); 234 235 // Skip relocations virtual sections. 236 if (S.isVirtual()) { 237 if (S.relocation_begin() != S.relocation_end()) 238 return make_error<JITLinkError>("Virtual section contains " 239 "relocations"); 240 continue; 241 } 242 243 auto NSec = 244 findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 245 if (!NSec) 246 return NSec.takeError(); 247 248 // Skip relocations for MachO sections without corresponding graph 249 // sections. 250 { 251 if (!NSec->GraphSection) { 252 LLVM_DEBUG({ 253 dbgs() << " Skipping relocations for MachO section " 254 << NSec->SegName << "/" << NSec->SectName 255 << " which has no associated graph section\n"; 256 }); 257 continue; 258 } 259 } 260 261 // Add relocations for section. 262 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 263 RelItr != RelEnd; ++RelItr) { 264 265 MachO::relocation_info RI = getRelocationInfo(RelItr); 266 267 // Find the address of the value to fix up. 268 auto FixupAddress = SectionAddress + (uint32_t)RI.r_address; 269 270 LLVM_DEBUG({ 271 dbgs() << " " << NSec->SectName << " + " 272 << formatv("{0:x8}", RI.r_address) << ":\n"; 273 }); 274 275 // Find the block that the fixup points to. 276 Block *BlockToFix = nullptr; 277 { 278 auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress); 279 if (!SymbolToFixOrErr) 280 return SymbolToFixOrErr.takeError(); 281 BlockToFix = &SymbolToFixOrErr->getBlock(); 282 } 283 284 if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) > 285 BlockToFix->getAddress() + BlockToFix->getContent().size()) 286 return make_error<JITLinkError>( 287 "Relocation extends past end of fixup block"); 288 289 // Get a pointer to the fixup content. 290 const char *FixupContent = BlockToFix->getContent().data() + 291 (FixupAddress - BlockToFix->getAddress()); 292 293 size_t FixupOffset = FixupAddress - BlockToFix->getAddress(); 294 295 // The target symbol and addend will be populated by the switch below. 296 Symbol *TargetSymbol = nullptr; 297 uint64_t Addend = 0; 298 299 // Validate the relocation kind. 300 auto MachORelocKind = getRelocKind(RI); 301 if (!MachORelocKind) 302 return MachORelocKind.takeError(); 303 304 Edge::Kind Kind = Edge::Invalid; 305 306 switch (*MachORelocKind) { 307 case MachOBranch32: 308 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 309 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 310 else 311 return TargetSymbolOrErr.takeError(); 312 Addend = *(const little32_t *)FixupContent; 313 Kind = x86_64::BranchPCRel32; 314 break; 315 case MachOPCRel32: 316 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 317 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 318 else 319 return TargetSymbolOrErr.takeError(); 320 Addend = *(const little32_t *)FixupContent - 4; 321 Kind = x86_64::Delta32; 322 break; 323 case MachOPCRel32GOTLoad: 324 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 325 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 326 else 327 return TargetSymbolOrErr.takeError(); 328 Addend = *(const little32_t *)FixupContent; 329 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable; 330 if (FixupOffset < 3) 331 return make_error<JITLinkError>("GOTLD at invalid offset " + 332 formatv("{0}", FixupOffset)); 333 break; 334 case MachOPCRel32GOT: 335 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 336 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 337 else 338 return TargetSymbolOrErr.takeError(); 339 Addend = *(const little32_t *)FixupContent - 4; 340 Kind = x86_64::RequestGOTAndTransformToDelta32; 341 break; 342 case MachOPCRel32TLV: 343 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 344 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 345 else 346 return TargetSymbolOrErr.takeError(); 347 Addend = *(const little32_t *)FixupContent; 348 Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable; 349 if (FixupOffset < 3) 350 return make_error<JITLinkError>("TLV at invalid offset " + 351 formatv("{0}", FixupOffset)); 352 break; 353 case MachOPointer32: 354 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 355 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 356 else 357 return TargetSymbolOrErr.takeError(); 358 Addend = *(const ulittle32_t *)FixupContent; 359 Kind = x86_64::Pointer32; 360 break; 361 case MachOPointer64: 362 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 363 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 364 else 365 return TargetSymbolOrErr.takeError(); 366 Addend = *(const ulittle64_t *)FixupContent; 367 Kind = x86_64::Pointer64; 368 break; 369 case MachOPointer64Anon: { 370 orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent); 371 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 372 if (!TargetNSec) 373 return TargetNSec.takeError(); 374 if (auto TargetSymbolOrErr = 375 findSymbolByAddress(*TargetNSec, TargetAddress)) 376 TargetSymbol = &*TargetSymbolOrErr; 377 else 378 return TargetSymbolOrErr.takeError(); 379 Addend = TargetAddress - TargetSymbol->getAddress(); 380 Kind = x86_64::Pointer64; 381 break; 382 } 383 case MachOPCRel32Minus1: 384 case MachOPCRel32Minus2: 385 case MachOPCRel32Minus4: 386 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 387 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 388 else 389 return TargetSymbolOrErr.takeError(); 390 Addend = *(const little32_t *)FixupContent - 4; 391 Kind = x86_64::Delta32; 392 break; 393 case MachOPCRel32Anon: { 394 orc::ExecutorAddr TargetAddress(FixupAddress + 4 + 395 *(const little32_t *)FixupContent); 396 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 397 if (!TargetNSec) 398 return TargetNSec.takeError(); 399 if (auto TargetSymbolOrErr = 400 findSymbolByAddress(*TargetNSec, TargetAddress)) 401 TargetSymbol = &*TargetSymbolOrErr; 402 else 403 return TargetSymbolOrErr.takeError(); 404 Addend = TargetAddress - TargetSymbol->getAddress() - 4; 405 Kind = x86_64::Delta32; 406 break; 407 } 408 case MachOPCRel32Minus1Anon: 409 case MachOPCRel32Minus2Anon: 410 case MachOPCRel32Minus4Anon: { 411 orc::ExecutorAddrDiff Delta = 412 4 + orc::ExecutorAddrDiff( 413 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon)); 414 orc::ExecutorAddr TargetAddress = 415 FixupAddress + Delta + *(const little32_t *)FixupContent; 416 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 417 if (!TargetNSec) 418 return TargetNSec.takeError(); 419 if (auto TargetSymbolOrErr = 420 findSymbolByAddress(*TargetNSec, TargetAddress)) 421 TargetSymbol = &*TargetSymbolOrErr; 422 else 423 return TargetSymbolOrErr.takeError(); 424 Addend = TargetAddress - TargetSymbol->getAddress() - Delta; 425 Kind = x86_64::Delta32; 426 break; 427 } 428 case MachOSubtractor32: 429 case MachOSubtractor64: { 430 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 431 // parsePairRelocation handles the paired reloc, and returns the 432 // edge kind to be used (either Delta32/Delta64, or 433 // NegDelta32/NegDelta64, depending on the direction of the 434 // subtraction) along with the addend. 435 auto PairInfo = 436 parsePairRelocation(*BlockToFix, *MachORelocKind, RI, 437 FixupAddress, FixupContent, ++RelItr, RelEnd); 438 if (!PairInfo) 439 return PairInfo.takeError(); 440 std::tie(Kind, TargetSymbol, Addend) = *PairInfo; 441 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 442 break; 443 } 444 } 445 446 LLVM_DEBUG({ 447 dbgs() << " "; 448 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 449 Addend); 450 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); 451 dbgs() << "\n"; 452 }); 453 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), 454 *TargetSymbol, Addend); 455 } 456 } 457 return Error::success(); 458 } 459 }; 460 461 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) { 462 x86_64::GOTTableManager GOT(G); 463 x86_64::PLTTableManager PLT(G, GOT); 464 visitExistingEdges(G, GOT, PLT); 465 return Error::success(); 466 } 467 468 } // namespace 469 470 namespace llvm { 471 namespace jitlink { 472 473 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { 474 friend class JITLinker<MachOJITLinker_x86_64>; 475 476 public: 477 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 478 std::unique_ptr<LinkGraph> G, 479 PassConfiguration PassConfig) 480 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 481 482 private: 483 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 484 return x86_64::applyFixup(G, B, E, nullptr); 485 } 486 }; 487 488 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromMachOObject_x86_64( 489 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { 490 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); 491 if (!MachOObj) 492 return MachOObj.takeError(); 493 494 auto Features = (*MachOObj)->getFeatures(); 495 if (!Features) 496 return Features.takeError(); 497 498 return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(SSP), 499 std::move(*Features)) 500 .buildGraph(); 501 } 502 503 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, 504 std::unique_ptr<JITLinkContext> Ctx) { 505 506 PassConfiguration Config; 507 508 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 509 // Add eh-frame passes. 510 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64()); 511 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64()); 512 513 // Add compact unwind splitter pass. 514 Config.PrePrunePasses.push_back( 515 CompactUnwindSplitter("__LD,__compact_unwind")); 516 517 // Add a mark-live pass. 518 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 519 Config.PrePrunePasses.push_back(std::move(MarkLive)); 520 else 521 Config.PrePrunePasses.push_back(markAllSymbolsLive); 522 523 // Resolve any external section start / end symbols. 524 Config.PostAllocationPasses.push_back( 525 createDefineExternalSectionStartAndEndSymbolsPass( 526 identifyMachOSectionStartAndEndSymbols)); 527 528 // Add an in-place GOT/Stubs pass. 529 Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64); 530 531 // Add GOT/Stubs optimizer pass. 532 Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses); 533 } 534 535 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 536 return Ctx->notifyFailed(std::move(Err)); 537 538 // Construct a JITLinker and run the link function. 539 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 540 } 541 542 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() { 543 return DWARFRecordSectionSplitter("__TEXT,__eh_frame"); 544 } 545 546 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() { 547 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize, 548 x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32, 549 x86_64::Delta64, x86_64::NegDelta32); 550 } 551 552 } // end namespace jitlink 553 } // end namespace llvm 554