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