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