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", jitlink::MemProt::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().JITDispatchFunction.getValue(), 177 JITSymbolFlags::Exported}}, 178 {ES.intern("___orc_rt_jit_dispatch_ctx"), 179 {EPC.getJITDispatchInfo().JITDispatchContext.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>(SPSExecutorAddr); 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<SPSExecutorAddr>(SPSExecutorAddr, 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 ExecutorAddr 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 ExecutorAddr Handle, StringRef SymbolName) { 446 LLVM_DEBUG({ 447 dbgs() << "MachOPlatform::rt_lookupSymbol(\"" 448 << formatv("{0:x}", Handle.getValue()) << "\")\n"; 449 }); 450 451 JITDylib *JD = nullptr; 452 453 { 454 std::lock_guard<std::mutex> Lock(PlatformMutex); 455 auto I = HeaderAddrToJITDylib.find(Handle.getValue()); 456 if (I != HeaderAddrToJITDylib.end()) 457 JD = I->second; 458 } 459 460 if (!JD) { 461 LLVM_DEBUG({ 462 dbgs() << " No JITDylib for handle " 463 << formatv("{0:x}", Handle.getValue()) << "\n"; 464 }); 465 SendResult(make_error<StringError>("No JITDylib associated with handle " + 466 formatv("{0:x}", Handle.getValue()), 467 inconvertibleErrorCode())); 468 return; 469 } 470 471 // Use functor class to work around XL build compiler issue on AIX. 472 class RtLookupNotifyComplete { 473 public: 474 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) 475 : SendResult(std::move(SendResult)) {} 476 void operator()(Expected<SymbolMap> Result) { 477 if (Result) { 478 assert(Result->size() == 1 && "Unexpected result map count"); 479 SendResult(ExecutorAddr(Result->begin()->second.getAddress())); 480 } else { 481 SendResult(Result.takeError()); 482 } 483 } 484 485 private: 486 SendSymbolAddressFn SendResult; 487 }; 488 489 // FIXME: Proper mangling. 490 auto MangledName = ("_" + SymbolName).str(); 491 ES.lookup( 492 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 493 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready, 494 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); 495 } 496 497 Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { 498 499 if (auto Err = lookupAndRecordAddrs( 500 ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), 501 {{ES.intern("___orc_rt_macho_platform_bootstrap"), 502 &orc_rt_macho_platform_bootstrap}, 503 {ES.intern("___orc_rt_macho_platform_shutdown"), 504 &orc_rt_macho_platform_shutdown}, 505 {ES.intern("___orc_rt_macho_register_object_sections"), 506 &orc_rt_macho_register_object_sections}, 507 {ES.intern("___orc_rt_macho_create_pthread_key"), 508 &orc_rt_macho_create_pthread_key}})) 509 return Err; 510 511 if (auto Err = ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap)) 512 return Err; 513 514 // FIXME: Ordering is fuzzy here. We're probably best off saying 515 // "behavior is undefined if code that uses the runtime is added before 516 // the platform constructor returns", then move all this to the constructor. 517 RuntimeBootstrapped = true; 518 std::vector<MachOPerObjectSectionsToRegister> DeferredPOSRs; 519 { 520 std::lock_guard<std::mutex> Lock(PlatformMutex); 521 DeferredPOSRs = std::move(BootstrapPOSRs); 522 } 523 524 for (auto &D : DeferredPOSRs) 525 if (auto Err = registerPerObjectSections(D)) 526 return Err; 527 528 return Error::success(); 529 } 530 531 Error MachOPlatform::registerInitInfo( 532 JITDylib &JD, ExecutorAddr ObjCImageInfoAddr, 533 ArrayRef<jitlink::Section *> InitSections) { 534 535 std::unique_lock<std::mutex> Lock(PlatformMutex); 536 537 MachOJITDylibInitializers *InitSeq = nullptr; 538 { 539 auto I = InitSeqs.find(&JD); 540 if (I == InitSeqs.end()) { 541 // If there's no init sequence entry yet then we need to look up the 542 // header symbol to force creation of one. 543 Lock.unlock(); 544 545 auto SearchOrder = 546 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); 547 if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError()) 548 return Err; 549 550 Lock.lock(); 551 I = InitSeqs.find(&JD); 552 assert(I != InitSeqs.end() && 553 "Entry missing after header symbol lookup?"); 554 } 555 InitSeq = &I->second; 556 } 557 558 InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr; 559 560 for (auto *Sec : InitSections) { 561 // FIXME: Avoid copy here. 562 jitlink::SectionRange R(*Sec); 563 InitSeq->InitSections[Sec->getName()].push_back( 564 {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())}); 565 } 566 567 return Error::success(); 568 } 569 570 Error MachOPlatform::registerPerObjectSections( 571 const MachOPerObjectSectionsToRegister &POSR) { 572 573 if (!orc_rt_macho_register_object_sections) 574 return make_error<StringError>("Attempting to register per-object " 575 "sections, but runtime support has not " 576 "been loaded yet", 577 inconvertibleErrorCode()); 578 579 Error ErrResult = Error::success(); 580 if (auto Err = ES.callSPSWrapper<shared::SPSError( 581 SPSMachOPerObjectSectionsToRegister)>( 582 orc_rt_macho_register_object_sections, ErrResult, POSR)) 583 return Err; 584 return ErrResult; 585 } 586 587 Expected<uint64_t> MachOPlatform::createPThreadKey() { 588 if (!orc_rt_macho_create_pthread_key) 589 return make_error<StringError>( 590 "Attempting to create pthread key in target, but runtime support has " 591 "not been loaded yet", 592 inconvertibleErrorCode()); 593 594 Expected<uint64_t> Result(0); 595 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( 596 orc_rt_macho_create_pthread_key, Result)) 597 return std::move(Err); 598 return Result; 599 } 600 601 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( 602 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 603 jitlink::PassConfiguration &Config) { 604 605 // If the initializer symbol is the MachOHeader start symbol then just add 606 // the macho header support passes. 607 if (MR.getInitializerSymbol() == MP.MachOHeaderStartSymbol) { 608 addMachOHeaderSupportPasses(MR, Config); 609 // The header materialization unit doesn't require any other support, so we 610 // can bail out early. 611 return; 612 } 613 614 // If the object contains initializers then add passes to record them. 615 if (MR.getInitializerSymbol()) 616 addInitializerSupportPasses(MR, Config); 617 618 // Add passes for eh-frame and TLV support. 619 addEHAndTLVSupportPasses(MR, Config); 620 } 621 622 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap 623 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( 624 MaterializationResponsibility &MR) { 625 std::lock_guard<std::mutex> Lock(PluginMutex); 626 auto I = InitSymbolDeps.find(&MR); 627 if (I != InitSymbolDeps.end()) { 628 SyntheticSymbolDependenciesMap Result; 629 Result[MR.getInitializerSymbol()] = std::move(I->second); 630 InitSymbolDeps.erase(&MR); 631 return Result; 632 } 633 return SyntheticSymbolDependenciesMap(); 634 } 635 636 void MachOPlatform::MachOPlatformPlugin::addInitializerSupportPasses( 637 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 638 639 /// Preserve init sections. 640 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) { 641 if (auto Err = preserveInitSections(G, MR)) 642 return Err; 643 return processObjCImageInfo(G, MR); 644 }); 645 646 Config.PostFixupPasses.push_back( 647 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 648 return registerInitSections(G, JD); 649 }); 650 } 651 652 void MachOPlatform::MachOPlatformPlugin::addMachOHeaderSupportPasses( 653 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 654 655 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()]( 656 jitlink::LinkGraph &G) -> Error { 657 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { 658 return Sym->getName() == *MP.MachOHeaderStartSymbol; 659 }); 660 assert(I != G.defined_symbols().end() && 661 "Missing MachO header start symbol"); 662 { 663 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 664 JITTargetAddress HeaderAddr = (*I)->getAddress(); 665 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; 666 assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists"); 667 MP.InitSeqs.insert(std::make_pair( 668 &JD, 669 MachOJITDylibInitializers(JD.getName(), ExecutorAddr(HeaderAddr)))); 670 } 671 return Error::success(); 672 }); 673 } 674 675 void MachOPlatform::MachOPlatformPlugin::addEHAndTLVSupportPasses( 676 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 677 678 // Insert TLV lowering at the start of the PostPrunePasses, since we want 679 // it to run before GOT/PLT lowering. 680 Config.PostPrunePasses.insert( 681 Config.PostPrunePasses.begin(), 682 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 683 return fixTLVSectionsAndEdges(G, JD); 684 }); 685 686 // Add a pass to register the final addresses of the eh-frame and TLV sections 687 // with the runtime. 688 Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 689 MachOPerObjectSectionsToRegister POSR; 690 691 if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) { 692 jitlink::SectionRange R(*EHFrameSection); 693 if (!R.empty()) 694 POSR.EHFrameSection = {ExecutorAddr(R.getStart()), 695 ExecutorAddr(R.getEnd())}; 696 } 697 698 // Get a pointer to the thread data section if there is one. It will be used 699 // below. 700 jitlink::Section *ThreadDataSection = 701 G.findSectionByName(ThreadDataSectionName); 702 703 // Handle thread BSS section if there is one. 704 if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) { 705 // If there's already a thread data section in this graph then merge the 706 // thread BSS section content into it, otherwise just treat the thread 707 // BSS section as the thread data section. 708 if (ThreadDataSection) 709 G.mergeSections(*ThreadDataSection, *ThreadBSSSection); 710 else 711 ThreadDataSection = ThreadBSSSection; 712 } 713 714 // Having merged thread BSS (if present) and thread data (if present), 715 // record the resulting section range. 716 if (ThreadDataSection) { 717 jitlink::SectionRange R(*ThreadDataSection); 718 if (!R.empty()) 719 POSR.ThreadDataSection = {ExecutorAddr(R.getStart()), 720 ExecutorAddr(R.getEnd())}; 721 } 722 723 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) { 724 725 // If we're still bootstrapping the runtime then just record this 726 // frame for now. 727 if (!MP.RuntimeBootstrapped) { 728 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 729 MP.BootstrapPOSRs.push_back(POSR); 730 return Error::success(); 731 } 732 733 // Otherwise register it immediately. 734 if (auto Err = MP.registerPerObjectSections(POSR)) 735 return Err; 736 } 737 738 return Error::success(); 739 }); 740 } 741 742 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections( 743 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 744 745 JITLinkSymbolSet InitSectionSymbols; 746 for (auto &InitSectionName : InitSectionNames) { 747 // Skip non-init sections. 748 auto *InitSection = G.findSectionByName(InitSectionName); 749 if (!InitSection) 750 continue; 751 752 // Make a pass over live symbols in the section: those blocks are already 753 // preserved. 754 DenseSet<jitlink::Block *> AlreadyLiveBlocks; 755 for (auto &Sym : InitSection->symbols()) { 756 auto &B = Sym->getBlock(); 757 if (Sym->isLive() && Sym->getOffset() == 0 && 758 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { 759 InitSectionSymbols.insert(Sym); 760 AlreadyLiveBlocks.insert(&B); 761 } 762 } 763 764 // Add anonymous symbols to preserve any not-already-preserved blocks. 765 for (auto *B : InitSection->blocks()) 766 if (!AlreadyLiveBlocks.count(B)) 767 InitSectionSymbols.insert( 768 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); 769 } 770 771 if (!InitSectionSymbols.empty()) { 772 std::lock_guard<std::mutex> Lock(PluginMutex); 773 InitSymbolDeps[&MR] = std::move(InitSectionSymbols); 774 } 775 776 return Error::success(); 777 } 778 779 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( 780 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 781 782 // If there's an ObjC imagine info then either 783 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In 784 // this case we name and record it. 785 // OR 786 // (2) We already have a recorded __objc_imageinfo for this JITDylib, 787 // in which case we just verify it. 788 auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName); 789 if (!ObjCImageInfo) 790 return Error::success(); 791 792 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); 793 794 // Check that the section is not empty if present. 795 if (llvm::empty(ObjCImageInfoBlocks)) 796 return make_error<StringError>("Empty " + ObjCImageInfoSectionName + 797 " section in " + G.getName(), 798 inconvertibleErrorCode()); 799 800 // Check that there's only one block in the section. 801 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) 802 return make_error<StringError>("Multiple blocks in " + 803 ObjCImageInfoSectionName + 804 " section in " + G.getName(), 805 inconvertibleErrorCode()); 806 807 // Check that the __objc_imageinfo section is unreferenced. 808 // FIXME: We could optimize this check if Symbols had a ref-count. 809 for (auto &Sec : G.sections()) { 810 if (&Sec != ObjCImageInfo) 811 for (auto *B : Sec.blocks()) 812 for (auto &E : B->edges()) 813 if (E.getTarget().isDefined() && 814 &E.getTarget().getBlock().getSection() == ObjCImageInfo) 815 return make_error<StringError>(ObjCImageInfoSectionName + 816 " is referenced within file " + 817 G.getName(), 818 inconvertibleErrorCode()); 819 } 820 821 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); 822 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); 823 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness()); 824 auto Flags = 825 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness()); 826 827 // Lock the mutex while we verify / update the ObjCImageInfos map. 828 std::lock_guard<std::mutex> Lock(PluginMutex); 829 830 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib()); 831 if (ObjCImageInfoItr != ObjCImageInfos.end()) { 832 // We've already registered an __objc_imageinfo section. Verify the 833 // content of this new section matches, then delete it. 834 if (ObjCImageInfoItr->second.first != Version) 835 return make_error<StringError>( 836 "ObjC version in " + G.getName() + 837 " does not match first registered version", 838 inconvertibleErrorCode()); 839 if (ObjCImageInfoItr->second.second != Flags) 840 return make_error<StringError>("ObjC flags in " + G.getName() + 841 " do not match first registered flags", 842 inconvertibleErrorCode()); 843 844 // __objc_imageinfo is valid. Delete the block. 845 for (auto *S : ObjCImageInfo->symbols()) 846 G.removeDefinedSymbol(*S); 847 G.removeBlock(ObjCImageInfoBlock); 848 } else { 849 // We haven't registered an __objc_imageinfo section yet. Register and 850 // move on. The section should already be marked no-dead-strip. 851 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags); 852 } 853 854 return Error::success(); 855 } 856 857 Error MachOPlatform::MachOPlatformPlugin::registerInitSections( 858 jitlink::LinkGraph &G, JITDylib &JD) { 859 860 ExecutorAddr ObjCImageInfoAddr; 861 SmallVector<jitlink::Section *> InitSections; 862 863 if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) { 864 if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) 865 ObjCImageInfoAddr.setValue(Addr); 866 } 867 868 for (auto InitSectionName : InitSectionNames) 869 if (auto *Sec = G.findSectionByName(InitSectionName)) 870 InitSections.push_back(Sec); 871 872 // Dump the scraped inits. 873 LLVM_DEBUG({ 874 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; 875 if (ObjCImageInfoAddr) 876 dbgs() << " " << ObjCImageInfoSectionName << ": " 877 << formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n"; 878 for (auto *Sec : InitSections) { 879 jitlink::SectionRange R(*Sec); 880 dbgs() << " " << Sec->getName() << ": " 881 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n"; 882 } 883 }); 884 885 return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections); 886 } 887 888 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( 889 jitlink::LinkGraph &G, JITDylib &JD) { 890 891 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr. 892 for (auto *Sym : G.external_symbols()) 893 if (Sym->getName() == "__tlv_bootstrap") { 894 Sym->setName("___orc_rt_macho_tlv_get_addr"); 895 break; 896 } 897 898 // Store key in __thread_vars struct fields. 899 if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) { 900 Optional<uint64_t> Key; 901 { 902 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 903 auto I = MP.JITDylibToPThreadKey.find(&JD); 904 if (I != MP.JITDylibToPThreadKey.end()) 905 Key = I->second; 906 } 907 908 if (!Key) { 909 if (auto KeyOrErr = MP.createPThreadKey()) 910 Key = *KeyOrErr; 911 else 912 return KeyOrErr.takeError(); 913 } 914 915 uint64_t PlatformKeyBits = 916 support::endian::byte_swap(*Key, G.getEndianness()); 917 918 for (auto *B : ThreadDataSec->blocks()) { 919 if (B->getSize() != 3 * G.getPointerSize()) 920 return make_error<StringError>("__thread_vars block at " + 921 formatv("{0:x}", B->getAddress()) + 922 " has unexpected size", 923 inconvertibleErrorCode()); 924 925 auto NewBlockContent = G.allocateBuffer(B->getSize()); 926 llvm::copy(B->getContent(), NewBlockContent.data()); 927 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits, 928 G.getPointerSize()); 929 B->setContent(NewBlockContent); 930 } 931 } 932 933 // Transform any TLV edges into GOT edges. 934 for (auto *B : G.blocks()) 935 for (auto &E : B->edges()) 936 if (E.getKind() == 937 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable) 938 E.setKind(jitlink::x86_64:: 939 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable); 940 941 return Error::success(); 942 } 943 944 } // End namespace orc. 945 } // End namespace llvm. 946