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