1 //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===// 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 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" 10 11 #include "llvm/BinaryFormat/MachO.h" 12 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 13 #include "llvm/ExecutionEngine/Orc/DebugUtils.h" 14 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 15 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" 16 #include "llvm/Support/BinaryByteStream.h" 17 #include "llvm/Support/Debug.h" 18 19 #define DEBUG_TYPE "orc" 20 21 using namespace llvm; 22 using namespace llvm::orc; 23 using namespace llvm::orc::shared; 24 25 namespace { 26 27 class MachOHeaderMaterializationUnit : public MaterializationUnit { 28 public: 29 MachOHeaderMaterializationUnit(MachOPlatform &MOP, 30 const SymbolStringPtr &HeaderStartSymbol) 31 : MaterializationUnit(createHeaderSymbols(MOP, HeaderStartSymbol), 32 HeaderStartSymbol), 33 MOP(MOP) {} 34 35 StringRef getName() const override { return "MachOHeaderMU"; } 36 37 void materialize(std::unique_ptr<MaterializationResponsibility> R) override { 38 unsigned PointerSize; 39 support::endianness Endianness; 40 const auto &TT = 41 MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); 42 43 switch (TT.getArch()) { 44 case Triple::aarch64: 45 case Triple::x86_64: 46 PointerSize = 8; 47 Endianness = support::endianness::little; 48 break; 49 default: 50 llvm_unreachable("Unrecognized architecture"); 51 } 52 53 auto G = std::make_unique<jitlink::LinkGraph>( 54 "<MachOHeaderMU>", TT, PointerSize, Endianness, 55 jitlink::getGenericEdgeKindName); 56 auto &HeaderSection = G->createSection("__header", sys::Memory::MF_READ); 57 auto &HeaderBlock = createHeaderBlock(*G, HeaderSection); 58 59 // Init symbol is header-start symbol. 60 G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(), 61 HeaderBlock.getSize(), jitlink::Linkage::Strong, 62 jitlink::Scope::Default, false, true); 63 for (auto &HS : AdditionalHeaderSymbols) 64 G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, 65 HeaderBlock.getSize(), jitlink::Linkage::Strong, 66 jitlink::Scope::Default, false, true); 67 68 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); 69 } 70 71 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} 72 73 private: 74 struct HeaderSymbol { 75 const char *Name; 76 uint64_t Offset; 77 }; 78 79 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = { 80 {"___mh_executable_header", 0}}; 81 82 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G, 83 jitlink::Section &HeaderSection) { 84 MachO::mach_header_64 Hdr; 85 Hdr.magic = MachO::MH_MAGIC_64; 86 switch (G.getTargetTriple().getArch()) { 87 case Triple::aarch64: 88 Hdr.cputype = MachO::CPU_TYPE_ARM64; 89 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; 90 break; 91 case Triple::x86_64: 92 Hdr.cputype = MachO::CPU_TYPE_X86_64; 93 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; 94 break; 95 default: 96 llvm_unreachable("Unrecognized architecture"); 97 } 98 Hdr.filetype = MachO::MH_DYLIB; // Custom file type? 99 Hdr.ncmds = 0; 100 Hdr.sizeofcmds = 0; 101 Hdr.flags = 0; 102 Hdr.reserved = 0; 103 104 if (G.getEndianness() != support::endian::system_endianness()) 105 MachO::swapStruct(Hdr); 106 107 auto HeaderContent = G.allocateString( 108 StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr))); 109 110 return G.createContentBlock(HeaderSection, HeaderContent, 0, 8, 0); 111 } 112 113 static SymbolFlagsMap 114 createHeaderSymbols(MachOPlatform &MOP, 115 const SymbolStringPtr &HeaderStartSymbol) { 116 SymbolFlagsMap HeaderSymbolFlags; 117 118 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; 119 for (auto &HS : AdditionalHeaderSymbols) 120 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] = 121 JITSymbolFlags::Exported; 122 123 return HeaderSymbolFlags; 124 } 125 126 MachOPlatform &MOP; 127 }; 128 129 constexpr MachOHeaderMaterializationUnit::HeaderSymbol 130 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[]; 131 132 StringRef EHFrameSectionName = "__TEXT,__eh_frame"; 133 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func"; 134 StringRef ObjCClassListSectionName = "__DATA,__objc_classlist"; 135 StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info"; 136 StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs"; 137 StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto"; 138 StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos"; 139 StringRef ThreadBSSSectionName = "__DATA,__thread_bss"; 140 StringRef ThreadDataSectionName = "__DATA,__thread_data"; 141 StringRef ThreadVarsSectionName = "__DATA,__thread_vars"; 142 143 StringRef InitSectionNames[] = { 144 ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName, 145 Swift5ProtosSectionName, Swift5ProtoSectionName}; 146 147 } // end anonymous namespace 148 149 namespace llvm { 150 namespace orc { 151 152 Expected<std::unique_ptr<MachOPlatform>> 153 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 154 JITDylib &PlatformJD, const char *OrcRuntimePath, 155 Optional<SymbolAliasMap> RuntimeAliases) { 156 157 auto &EPC = ES.getExecutorProcessControl(); 158 159 // If the target is not supported then bail out immediately. 160 if (!supportedTarget(EPC.getTargetTriple())) 161 return make_error<StringError>("Unsupported MachOPlatform triple: " + 162 EPC.getTargetTriple().str(), 163 inconvertibleErrorCode()); 164 165 // Create default aliases if the caller didn't supply any. 166 if (!RuntimeAliases) 167 RuntimeAliases = standardPlatformAliases(ES); 168 169 // Define the aliases. 170 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) 171 return std::move(Err); 172 173 // Add JIT-dispatch function support symbols. 174 if (auto Err = PlatformJD.define(absoluteSymbols( 175 {{ES.intern("___orc_rt_jit_dispatch"), 176 {EPC.getJITDispatchInfo().JITDispatchFunctionAddress.getValue(), 177 JITSymbolFlags::Exported}}, 178 {ES.intern("___orc_rt_jit_dispatch_ctx"), 179 {EPC.getJITDispatchInfo().JITDispatchContextAddress.getValue(), 180 JITSymbolFlags::Exported}}}))) 181 return std::move(Err); 182 183 // Create a generator for the ORC runtime archive. 184 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load( 185 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple()); 186 if (!OrcRuntimeArchiveGenerator) 187 return OrcRuntimeArchiveGenerator.takeError(); 188 189 // Create the instance. 190 Error Err = Error::success(); 191 auto P = std::unique_ptr<MachOPlatform>( 192 new MachOPlatform(ES, ObjLinkingLayer, PlatformJD, 193 std::move(*OrcRuntimeArchiveGenerator), Err)); 194 if (Err) 195 return std::move(Err); 196 return std::move(P); 197 } 198 199 Error MachOPlatform::setupJITDylib(JITDylib &JD) { 200 return JD.define(std::make_unique<MachOHeaderMaterializationUnit>( 201 *this, MachOHeaderStartSymbol)); 202 } 203 204 Error MachOPlatform::notifyAdding(ResourceTracker &RT, 205 const MaterializationUnit &MU) { 206 auto &JD = RT.getJITDylib(); 207 const auto &InitSym = MU.getInitializerSymbol(); 208 if (!InitSym) 209 return Error::success(); 210 211 RegisteredInitSymbols[&JD].add(InitSym, 212 SymbolLookupFlags::WeaklyReferencedSymbol); 213 LLVM_DEBUG({ 214 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU " 215 << MU.getName() << "\n"; 216 }); 217 return Error::success(); 218 } 219 220 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) { 221 llvm_unreachable("Not supported yet"); 222 } 223 224 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, 225 ArrayRef<std::pair<const char *, const char *>> AL) { 226 for (auto &KV : AL) { 227 auto AliasName = ES.intern(KV.first); 228 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map"); 229 Aliases[std::move(AliasName)] = {ES.intern(KV.second), 230 JITSymbolFlags::Exported}; 231 } 232 } 233 234 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) { 235 SymbolAliasMap Aliases; 236 addAliases(ES, Aliases, requiredCXXAliases()); 237 addAliases(ES, Aliases, standardRuntimeUtilityAliases()); 238 return Aliases; 239 } 240 241 ArrayRef<std::pair<const char *, const char *>> 242 MachOPlatform::requiredCXXAliases() { 243 static const std::pair<const char *, const char *> RequiredCXXAliases[] = { 244 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}}; 245 246 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); 247 } 248 249 ArrayRef<std::pair<const char *, const char *>> 250 MachOPlatform::standardRuntimeUtilityAliases() { 251 static const std::pair<const char *, const char *> 252 StandardRuntimeUtilityAliases[] = { 253 {"___orc_rt_run_program", "___orc_rt_macho_run_program"}, 254 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}}; 255 256 return ArrayRef<std::pair<const char *, const char *>>( 257 StandardRuntimeUtilityAliases); 258 } 259 260 bool MachOPlatform::isInitializerSection(StringRef SegName, 261 StringRef SectName) { 262 for (auto &Name : InitSectionNames) { 263 if (Name.startswith(SegName) && Name.substr(7) == SectName) 264 return true; 265 } 266 return false; 267 } 268 269 bool MachOPlatform::supportedTarget(const Triple &TT) { 270 switch (TT.getArch()) { 271 case Triple::x86_64: 272 return true; 273 default: 274 return false; 275 } 276 } 277 278 MachOPlatform::MachOPlatform( 279 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 280 JITDylib &PlatformJD, 281 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) 282 : ES(ES), ObjLinkingLayer(ObjLinkingLayer), 283 MachOHeaderStartSymbol(ES.intern("___dso_handle")) { 284 ErrorAsOutParameter _(&Err); 285 286 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this)); 287 288 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); 289 290 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating 291 // the platform now), so set it up. 292 if (auto E2 = setupJITDylib(PlatformJD)) { 293 Err = std::move(E2); 294 return; 295 } 296 297 RegisteredInitSymbols[&PlatformJD].add( 298 MachOHeaderStartSymbol, SymbolLookupFlags::WeaklyReferencedSymbol); 299 300 // Associate wrapper function tags with JIT-side function implementations. 301 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { 302 Err = std::move(E2); 303 return; 304 } 305 306 // Lookup addresses of runtime functions callable by the platform, 307 // call the platform bootstrap function to initialize the platform-state 308 // object in the executor. 309 if (auto E2 = bootstrapMachORuntime(PlatformJD)) { 310 Err = std::move(E2); 311 return; 312 } 313 } 314 315 Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { 316 ExecutionSession::JITDispatchHandlerAssociationMap WFs; 317 318 using GetInitializersSPSSig = 319 SPSExpected<SPSMachOJITDylibInitializerSequence>(SPSString); 320 WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] = 321 ES.wrapAsyncWithSPS<GetInitializersSPSSig>( 322 this, &MachOPlatform::rt_getInitializers); 323 324 using GetDeinitializersSPSSig = 325 SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddress); 326 WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] = 327 ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>( 328 this, &MachOPlatform::rt_getDeinitializers); 329 330 using LookupSymbolSPSSig = 331 SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString); 332 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] = 333 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, 334 &MachOPlatform::rt_lookupSymbol); 335 336 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); 337 } 338 339 void MachOPlatform::getInitializersBuildSequencePhase( 340 SendInitializerSequenceFn SendResult, JITDylib &JD, 341 std::vector<JITDylibSP> DFSLinkOrder) { 342 MachOJITDylibInitializerSequence FullInitSeq; 343 { 344 std::lock_guard<std::mutex> Lock(PlatformMutex); 345 for (auto &InitJD : reverse(DFSLinkOrder)) { 346 LLVM_DEBUG({ 347 dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName() 348 << "\" to sequence\n"; 349 }); 350 auto ISItr = InitSeqs.find(InitJD.get()); 351 if (ISItr != InitSeqs.end()) { 352 FullInitSeq.emplace_back(std::move(ISItr->second)); 353 InitSeqs.erase(ISItr); 354 } 355 } 356 } 357 358 SendResult(std::move(FullInitSeq)); 359 } 360 361 void MachOPlatform::getInitializersLookupPhase( 362 SendInitializerSequenceFn SendResult, JITDylib &JD) { 363 364 auto DFSLinkOrder = JD.getDFSLinkOrder(); 365 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; 366 ES.runSessionLocked([&]() { 367 for (auto &InitJD : DFSLinkOrder) { 368 auto RISItr = RegisteredInitSymbols.find(InitJD.get()); 369 if (RISItr != RegisteredInitSymbols.end()) { 370 NewInitSymbols[InitJD.get()] = std::move(RISItr->second); 371 RegisteredInitSymbols.erase(RISItr); 372 } 373 } 374 }); 375 376 // If there are no further init symbols to look up then move on to the next 377 // phase. 378 if (NewInitSymbols.empty()) { 379 getInitializersBuildSequencePhase(std::move(SendResult), JD, 380 std::move(DFSLinkOrder)); 381 return; 382 } 383 384 // Otherwise issue a lookup and re-run this phase when it completes. 385 lookupInitSymbolsAsync( 386 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable { 387 if (Err) 388 SendResult(std::move(Err)); 389 else 390 getInitializersLookupPhase(std::move(SendResult), JD); 391 }, 392 ES, std::move(NewInitSymbols)); 393 } 394 395 void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult, 396 StringRef JDName) { 397 LLVM_DEBUG({ 398 dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName << "\")\n"; 399 }); 400 401 JITDylib *JD = ES.getJITDylibByName(JDName); 402 if (!JD) { 403 LLVM_DEBUG({ 404 dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; 405 }); 406 SendResult(make_error<StringError>("No JITDylib named " + JDName, 407 inconvertibleErrorCode())); 408 return; 409 } 410 411 getInitializersLookupPhase(std::move(SendResult), *JD); 412 } 413 414 void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult, 415 ExecutorAddress Handle) { 416 LLVM_DEBUG({ 417 dbgs() << "MachOPlatform::rt_getDeinitializers(\"" 418 << formatv("{0:x}", Handle.getValue()) << "\")\n"; 419 }); 420 421 JITDylib *JD = nullptr; 422 423 { 424 std::lock_guard<std::mutex> Lock(PlatformMutex); 425 auto I = HeaderAddrToJITDylib.find(Handle.getValue()); 426 if (I != HeaderAddrToJITDylib.end()) 427 JD = I->second; 428 } 429 430 if (!JD) { 431 LLVM_DEBUG({ 432 dbgs() << " No JITDylib for handle " 433 << formatv("{0:x}", Handle.getValue()) << "\n"; 434 }); 435 SendResult(make_error<StringError>("No JITDylib associated with handle " + 436 formatv("{0:x}", Handle.getValue()), 437 inconvertibleErrorCode())); 438 return; 439 } 440 441 SendResult(MachOJITDylibDeinitializerSequence()); 442 } 443 444 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, 445 ExecutorAddress Handle, 446 StringRef SymbolName) { 447 LLVM_DEBUG({ 448 dbgs() << "MachOPlatform::rt_lookupSymbol(\"" 449 << formatv("{0:x}", Handle.getValue()) << "\")\n"; 450 }); 451 452 JITDylib *JD = nullptr; 453 454 { 455 std::lock_guard<std::mutex> Lock(PlatformMutex); 456 auto I = HeaderAddrToJITDylib.find(Handle.getValue()); 457 if (I != HeaderAddrToJITDylib.end()) 458 JD = I->second; 459 } 460 461 if (!JD) { 462 LLVM_DEBUG({ 463 dbgs() << " No JITDylib for handle " 464 << formatv("{0:x}", Handle.getValue()) << "\n"; 465 }); 466 SendResult(make_error<StringError>("No JITDylib associated with handle " + 467 formatv("{0:x}", Handle.getValue()), 468 inconvertibleErrorCode())); 469 return; 470 } 471 472 // Use functor class to work around XL build compiler issue on AIX. 473 class RtLookupNotifyComplete { 474 public: 475 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) 476 : SendResult(std::move(SendResult)) {} 477 void operator()(Expected<SymbolMap> Result) { 478 if (Result) { 479 assert(Result->size() == 1 && "Unexpected result map count"); 480 SendResult(ExecutorAddress(Result->begin()->second.getAddress())); 481 } else { 482 SendResult(Result.takeError()); 483 } 484 } 485 486 private: 487 SendSymbolAddressFn SendResult; 488 }; 489 490 // FIXME: Proper mangling. 491 auto MangledName = ("_" + SymbolName).str(); 492 ES.lookup( 493 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 494 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready, 495 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); 496 } 497 498 Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { 499 500 if (auto Err = lookupAndRecordAddrs( 501 ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), 502 {{ES.intern("___orc_rt_macho_platform_bootstrap"), 503 &orc_rt_macho_platform_bootstrap}, 504 {ES.intern("___orc_rt_macho_platform_shutdown"), 505 &orc_rt_macho_platform_shutdown}, 506 {ES.intern("___orc_rt_macho_register_object_sections"), 507 &orc_rt_macho_register_object_sections}, 508 {ES.intern("___orc_rt_macho_create_pthread_key"), 509 &orc_rt_macho_create_pthread_key}})) 510 return Err; 511 512 if (auto Err = 513 ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap.getValue())) 514 return Err; 515 516 // FIXME: Ordering is fuzzy here. We're probably best off saying 517 // "behavior is undefined if code that uses the runtime is added before 518 // the platform constructor returns", then move all this to the constructor. 519 RuntimeBootstrapped = true; 520 std::vector<MachOPerObjectSectionsToRegister> DeferredPOSRs; 521 { 522 std::lock_guard<std::mutex> Lock(PlatformMutex); 523 DeferredPOSRs = std::move(BootstrapPOSRs); 524 } 525 526 for (auto &D : DeferredPOSRs) 527 if (auto Err = registerPerObjectSections(D)) 528 return Err; 529 530 return Error::success(); 531 } 532 533 Error MachOPlatform::registerInitInfo( 534 JITDylib &JD, ExecutorAddress ObjCImageInfoAddr, 535 ArrayRef<jitlink::Section *> InitSections) { 536 537 std::unique_lock<std::mutex> Lock(PlatformMutex); 538 539 MachOJITDylibInitializers *InitSeq = nullptr; 540 { 541 auto I = InitSeqs.find(&JD); 542 if (I == InitSeqs.end()) { 543 // If there's no init sequence entry yet then we need to look up the 544 // header symbol to force creation of one. 545 Lock.unlock(); 546 547 auto SearchOrder = 548 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); 549 if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError()) 550 return Err; 551 552 Lock.lock(); 553 I = InitSeqs.find(&JD); 554 assert(I != InitSeqs.end() && 555 "Entry missing after header symbol lookup?"); 556 } 557 InitSeq = &I->second; 558 } 559 560 InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr; 561 562 for (auto *Sec : InitSections) { 563 // FIXME: Avoid copy here. 564 jitlink::SectionRange R(*Sec); 565 InitSeq->InitSections[Sec->getName()].push_back( 566 {ExecutorAddress(R.getStart()), ExecutorAddress(R.getEnd())}); 567 } 568 569 return Error::success(); 570 } 571 572 Error MachOPlatform::registerPerObjectSections( 573 const MachOPerObjectSectionsToRegister &POSR) { 574 575 if (!orc_rt_macho_register_object_sections) 576 return make_error<StringError>("Attempting to register per-object " 577 "sections, but runtime support has not " 578 "been loaded yet", 579 inconvertibleErrorCode()); 580 581 Error ErrResult = Error::success(); 582 if (auto Err = ES.callSPSWrapper<shared::SPSError( 583 SPSMachOPerObjectSectionsToRegister)>( 584 orc_rt_macho_register_object_sections.getValue(), ErrResult, POSR)) 585 return Err; 586 return ErrResult; 587 } 588 589 Expected<uint64_t> MachOPlatform::createPThreadKey() { 590 if (!orc_rt_macho_create_pthread_key) 591 return make_error<StringError>( 592 "Attempting to create pthread key in target, but runtime support has " 593 "not been loaded yet", 594 inconvertibleErrorCode()); 595 596 Expected<uint64_t> Result(0); 597 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( 598 orc_rt_macho_create_pthread_key.getValue(), Result)) 599 return std::move(Err); 600 return Result; 601 } 602 603 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( 604 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 605 jitlink::PassConfiguration &Config) { 606 607 // If the initializer symbol is the MachOHeader start symbol then just add 608 // the macho header support passes. 609 if (MR.getInitializerSymbol() == MP.MachOHeaderStartSymbol) { 610 addMachOHeaderSupportPasses(MR, Config); 611 // The header materialization unit doesn't require any other support, so we 612 // can bail out early. 613 return; 614 } 615 616 // If the object contains initializers then add passes to record them. 617 if (MR.getInitializerSymbol()) 618 addInitializerSupportPasses(MR, Config); 619 620 // Add passes for eh-frame and TLV support. 621 addEHAndTLVSupportPasses(MR, Config); 622 } 623 624 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap 625 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( 626 MaterializationResponsibility &MR) { 627 std::lock_guard<std::mutex> Lock(PluginMutex); 628 auto I = InitSymbolDeps.find(&MR); 629 if (I != InitSymbolDeps.end()) { 630 SyntheticSymbolDependenciesMap Result; 631 Result[MR.getInitializerSymbol()] = std::move(I->second); 632 InitSymbolDeps.erase(&MR); 633 return Result; 634 } 635 return SyntheticSymbolDependenciesMap(); 636 } 637 638 void MachOPlatform::MachOPlatformPlugin::addInitializerSupportPasses( 639 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 640 641 /// Preserve init sections. 642 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) { 643 if (auto Err = preserveInitSections(G, MR)) 644 return Err; 645 return processObjCImageInfo(G, MR); 646 }); 647 648 Config.PostFixupPasses.push_back( 649 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 650 return registerInitSections(G, JD); 651 }); 652 } 653 654 void MachOPlatform::MachOPlatformPlugin::addMachOHeaderSupportPasses( 655 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 656 657 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()]( 658 jitlink::LinkGraph &G) -> Error { 659 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { 660 return Sym->getName() == *MP.MachOHeaderStartSymbol; 661 }); 662 assert(I != G.defined_symbols().end() && 663 "Missing MachO header start symbol"); 664 { 665 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 666 JITTargetAddress HeaderAddr = (*I)->getAddress(); 667 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; 668 assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists"); 669 MP.InitSeqs.insert( 670 std::make_pair(&JD, MachOJITDylibInitializers( 671 JD.getName(), ExecutorAddress(HeaderAddr)))); 672 } 673 return Error::success(); 674 }); 675 } 676 677 void MachOPlatform::MachOPlatformPlugin::addEHAndTLVSupportPasses( 678 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 679 680 // Insert TLV lowering at the start of the PostPrunePasses, since we want 681 // it to run before GOT/PLT lowering. 682 Config.PostPrunePasses.insert( 683 Config.PostPrunePasses.begin(), 684 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 685 return fixTLVSectionsAndEdges(G, JD); 686 }); 687 688 // Add a pass to register the final addresses of the eh-frame and TLV sections 689 // with the runtime. 690 Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 691 MachOPerObjectSectionsToRegister POSR; 692 693 if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) { 694 jitlink::SectionRange R(*EHFrameSection); 695 if (!R.empty()) 696 POSR.EHFrameSection = {ExecutorAddress(R.getStart()), 697 ExecutorAddress(R.getEnd())}; 698 } 699 700 // Get a pointer to the thread data section if there is one. It will be used 701 // below. 702 jitlink::Section *ThreadDataSection = 703 G.findSectionByName(ThreadDataSectionName); 704 705 // Handle thread BSS section if there is one. 706 if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) { 707 // If there's already a thread data section in this graph then merge the 708 // thread BSS section content into it, otherwise just treat the thread 709 // BSS section as the thread data section. 710 if (ThreadDataSection) 711 G.mergeSections(*ThreadDataSection, *ThreadBSSSection); 712 else 713 ThreadDataSection = ThreadBSSSection; 714 } 715 716 // Having merged thread BSS (if present) and thread data (if present), 717 // record the resulting section range. 718 if (ThreadDataSection) { 719 jitlink::SectionRange R(*ThreadDataSection); 720 if (!R.empty()) 721 POSR.ThreadDataSection = {ExecutorAddress(R.getStart()), 722 ExecutorAddress(R.getEnd())}; 723 } 724 725 if (POSR.EHFrameSection.StartAddress || 726 POSR.ThreadDataSection.StartAddress) { 727 728 // If we're still bootstrapping the runtime then just record this 729 // frame for now. 730 if (!MP.RuntimeBootstrapped) { 731 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 732 MP.BootstrapPOSRs.push_back(POSR); 733 return Error::success(); 734 } 735 736 // Otherwise register it immediately. 737 if (auto Err = MP.registerPerObjectSections(POSR)) 738 return Err; 739 } 740 741 return Error::success(); 742 }); 743 } 744 745 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections( 746 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 747 748 JITLinkSymbolSet InitSectionSymbols; 749 for (auto &InitSectionName : InitSectionNames) { 750 // Skip non-init sections. 751 auto *InitSection = G.findSectionByName(InitSectionName); 752 if (!InitSection) 753 continue; 754 755 // Make a pass over live symbols in the section: those blocks are already 756 // preserved. 757 DenseSet<jitlink::Block *> AlreadyLiveBlocks; 758 for (auto &Sym : InitSection->symbols()) { 759 auto &B = Sym->getBlock(); 760 if (Sym->isLive() && Sym->getOffset() == 0 && 761 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { 762 InitSectionSymbols.insert(Sym); 763 AlreadyLiveBlocks.insert(&B); 764 } 765 } 766 767 // Add anonymous symbols to preserve any not-already-preserved blocks. 768 for (auto *B : InitSection->blocks()) 769 if (!AlreadyLiveBlocks.count(B)) 770 InitSectionSymbols.insert( 771 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); 772 } 773 774 if (!InitSectionSymbols.empty()) { 775 std::lock_guard<std::mutex> Lock(PluginMutex); 776 InitSymbolDeps[&MR] = std::move(InitSectionSymbols); 777 } 778 779 return Error::success(); 780 } 781 782 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( 783 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 784 785 // If there's an ObjC imagine info then either 786 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In 787 // this case we name and record it. 788 // OR 789 // (2) We already have a recorded __objc_imageinfo for this JITDylib, 790 // in which case we just verify it. 791 auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName); 792 if (!ObjCImageInfo) 793 return Error::success(); 794 795 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); 796 797 // Check that the section is not empty if present. 798 if (llvm::empty(ObjCImageInfoBlocks)) 799 return make_error<StringError>("Empty " + ObjCImageInfoSectionName + 800 " section in " + G.getName(), 801 inconvertibleErrorCode()); 802 803 // Check that there's only one block in the section. 804 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) 805 return make_error<StringError>("Multiple blocks in " + 806 ObjCImageInfoSectionName + 807 " section in " + G.getName(), 808 inconvertibleErrorCode()); 809 810 // Check that the __objc_imageinfo section is unreferenced. 811 // FIXME: We could optimize this check if Symbols had a ref-count. 812 for (auto &Sec : G.sections()) { 813 if (&Sec != ObjCImageInfo) 814 for (auto *B : Sec.blocks()) 815 for (auto &E : B->edges()) 816 if (E.getTarget().isDefined() && 817 &E.getTarget().getBlock().getSection() == ObjCImageInfo) 818 return make_error<StringError>(ObjCImageInfoSectionName + 819 " is referenced within file " + 820 G.getName(), 821 inconvertibleErrorCode()); 822 } 823 824 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); 825 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); 826 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness()); 827 auto Flags = 828 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness()); 829 830 // Lock the mutex while we verify / update the ObjCImageInfos map. 831 std::lock_guard<std::mutex> Lock(PluginMutex); 832 833 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib()); 834 if (ObjCImageInfoItr != ObjCImageInfos.end()) { 835 // We've already registered an __objc_imageinfo section. Verify the 836 // content of this new section matches, then delete it. 837 if (ObjCImageInfoItr->second.first != Version) 838 return make_error<StringError>( 839 "ObjC version in " + G.getName() + 840 " does not match first registered version", 841 inconvertibleErrorCode()); 842 if (ObjCImageInfoItr->second.second != Flags) 843 return make_error<StringError>("ObjC flags in " + G.getName() + 844 " do not match first registered flags", 845 inconvertibleErrorCode()); 846 847 // __objc_imageinfo is valid. Delete the block. 848 for (auto *S : ObjCImageInfo->symbols()) 849 G.removeDefinedSymbol(*S); 850 G.removeBlock(ObjCImageInfoBlock); 851 } else { 852 // We haven't registered an __objc_imageinfo section yet. Register and 853 // move on. The section should already be marked no-dead-strip. 854 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags); 855 } 856 857 return Error::success(); 858 } 859 860 Error MachOPlatform::MachOPlatformPlugin::registerInitSections( 861 jitlink::LinkGraph &G, JITDylib &JD) { 862 863 ExecutorAddress ObjCImageInfoAddr; 864 SmallVector<jitlink::Section *> InitSections; 865 866 if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) { 867 if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) 868 ObjCImageInfoAddr.setValue(Addr); 869 } 870 871 for (auto InitSectionName : InitSectionNames) 872 if (auto *Sec = G.findSectionByName(InitSectionName)) 873 InitSections.push_back(Sec); 874 875 // Dump the scraped inits. 876 LLVM_DEBUG({ 877 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; 878 if (ObjCImageInfoAddr) 879 dbgs() << " " << ObjCImageInfoSectionName << ": " 880 << formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n"; 881 for (auto *Sec : InitSections) { 882 jitlink::SectionRange R(*Sec); 883 dbgs() << " " << Sec->getName() << ": " 884 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n"; 885 } 886 }); 887 888 return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections); 889 } 890 891 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( 892 jitlink::LinkGraph &G, JITDylib &JD) { 893 894 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr. 895 for (auto *Sym : G.external_symbols()) 896 if (Sym->getName() == "__tlv_bootstrap") { 897 Sym->setName("___orc_rt_macho_tlv_get_addr"); 898 break; 899 } 900 901 // Store key in __thread_vars struct fields. 902 if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) { 903 Optional<uint64_t> Key; 904 { 905 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 906 auto I = MP.JITDylibToPThreadKey.find(&JD); 907 if (I != MP.JITDylibToPThreadKey.end()) 908 Key = I->second; 909 } 910 911 if (!Key) { 912 if (auto KeyOrErr = MP.createPThreadKey()) 913 Key = *KeyOrErr; 914 else 915 return KeyOrErr.takeError(); 916 } 917 918 uint64_t PlatformKeyBits = 919 support::endian::byte_swap(*Key, G.getEndianness()); 920 921 for (auto *B : ThreadDataSec->blocks()) { 922 if (B->getSize() != 3 * G.getPointerSize()) 923 return make_error<StringError>("__thread_vars block at " + 924 formatv("{0:x}", B->getAddress()) + 925 " has unexpected size", 926 inconvertibleErrorCode()); 927 928 auto NewBlockContent = G.allocateBuffer(B->getSize()); 929 llvm::copy(B->getContent(), NewBlockContent.data()); 930 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits, 931 G.getPointerSize()); 932 B->setContent(NewBlockContent); 933 } 934 } 935 936 // Transform any TLV edges into GOT edges. 937 for (auto *B : G.blocks()) 938 for (auto &E : B->edges()) 939 if (E.getKind() == 940 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable) 941 E.setKind(jitlink::x86_64:: 942 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable); 943 944 return Error::success(); 945 } 946 947 } // End namespace orc. 948 } // End namespace llvm. 949