diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp | 615 |
1 files changed, 440 insertions, 175 deletions
diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index a3a766d602c1..9057300bf043 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -15,6 +15,7 @@ #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" +#include "llvm/ExecutionEngine/Orc/MachOBuilder.h" #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Debug.h" @@ -34,6 +35,8 @@ using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>; using SPSMachOJITDylibDepInfoMap = SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>; +class SPSMachOExecutorSymbolFlags; + template <> class SPSSerializationTraits<SPSMachOJITDylibDepInfo, MachOPlatform::MachOJITDylibDepInfo> { @@ -55,23 +58,54 @@ public: } }; +template <> +class SPSSerializationTraits<SPSMachOExecutorSymbolFlags, + MachOPlatform::MachOExecutorSymbolFlags> { +private: + using UT = std::underlying_type_t<MachOPlatform::MachOExecutorSymbolFlags>; + +public: + static size_t size(const MachOPlatform::MachOExecutorSymbolFlags &SF) { + return sizeof(UT); + } + + static bool serialize(SPSOutputBuffer &OB, + const MachOPlatform::MachOExecutorSymbolFlags &SF) { + return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF)); + } + + static bool deserialize(SPSInputBuffer &IB, + MachOPlatform::MachOExecutorSymbolFlags &SF) { + UT Tmp; + if (!SPSArgList<UT>::deserialize(IB, Tmp)) + return false; + SF = static_cast<MachOPlatform::MachOExecutorSymbolFlags>(Tmp); + return true; + } +}; + } // namespace shared } // namespace orc } // namespace llvm namespace { +using SPSRegisterSymbolsArgs = + SPSArgList<SPSExecutorAddr, + SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr, + SPSMachOExecutorSymbolFlags>>>; + std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP, std::string Name) { unsigned PointerSize; - support::endianness Endianness; + llvm::endianness Endianness; const auto &TT = MOP.getExecutionSession().getTargetTriple(); switch (TT.getArch()) { case Triple::aarch64: case Triple::x86_64: PointerSize = 8; - Endianness = support::endianness::little; + Endianness = llvm::endianness::little; break; default: llvm_unreachable("Unrecognized architecture"); @@ -82,119 +116,32 @@ std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP, jitlink::getGenericEdgeKindName); } -// Generates a MachO header. -class MachOHeaderMaterializationUnit : public MaterializationUnit { -public: - MachOHeaderMaterializationUnit(MachOPlatform &MOP, - const SymbolStringPtr &HeaderStartSymbol) - : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)), - MOP(MOP) {} - - StringRef getName() const override { return "MachOHeaderMU"; } - - void materialize(std::unique_ptr<MaterializationResponsibility> R) override { - auto G = createPlatformGraph(MOP, "<MachOHeaderMU>"); - addMachOHeader(*G, MOP, R->getInitializerSymbol()); - MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); - } - - void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} - - static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP, - const SymbolStringPtr &InitializerSymbol) { - auto &HeaderSection = G.createSection("__header", MemProt::Read); - auto &HeaderBlock = createHeaderBlock(G, HeaderSection); - - // Init symbol is header-start symbol. - G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, - HeaderBlock.getSize(), jitlink::Linkage::Strong, - jitlink::Scope::Default, false, true); - for (auto &HS : AdditionalHeaderSymbols) - G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(), - jitlink::Linkage::Strong, jitlink::Scope::Default, - false, true); - } - -private: - struct HeaderSymbol { - const char *Name; - uint64_t Offset; - }; - - static constexpr HeaderSymbol AdditionalHeaderSymbols[] = { - {"___mh_executable_header", 0}}; - - static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G, - jitlink::Section &HeaderSection) { - MachO::mach_header_64 Hdr; - Hdr.magic = MachO::MH_MAGIC_64; - switch (G.getTargetTriple().getArch()) { - case Triple::aarch64: - Hdr.cputype = MachO::CPU_TYPE_ARM64; - Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; - break; - case Triple::x86_64: - Hdr.cputype = MachO::CPU_TYPE_X86_64; - Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; - break; - default: - llvm_unreachable("Unrecognized architecture"); - } - Hdr.filetype = MachO::MH_DYLIB; // Custom file type? - Hdr.ncmds = 0; - Hdr.sizeofcmds = 0; - Hdr.flags = 0; - Hdr.reserved = 0; - - if (G.getEndianness() != support::endian::system_endianness()) - MachO::swapStruct(Hdr); - - auto HeaderContent = G.allocateContent( - ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr))); - - return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8, - 0); - } - - static MaterializationUnit::Interface - createHeaderInterface(MachOPlatform &MOP, - const SymbolStringPtr &HeaderStartSymbol) { - SymbolFlagsMap HeaderSymbolFlags; - - HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; - for (auto &HS : AdditionalHeaderSymbols) - HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] = - JITSymbolFlags::Exported; - - return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), - HeaderStartSymbol); - } - - MachOPlatform &MOP; -}; - -constexpr MachOHeaderMaterializationUnit::HeaderSymbol - MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[]; - // Creates a Bootstrap-Complete LinkGraph to run deferred actions. class MachOPlatformCompleteBootstrapMaterializationUnit : public MaterializationUnit { public: + using SymbolTableVector = + SmallVector<std::tuple<ExecutorAddr, ExecutorAddr, + MachOPlatform::MachOExecutorSymbolFlags>>; + MachOPlatformCompleteBootstrapMaterializationUnit( MachOPlatform &MOP, StringRef PlatformJDName, - SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs, + SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab, + shared::AllocActions DeferredAAs, ExecutorAddr MachOHeaderAddr, ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown, ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib, - ExecutorAddr MachOHeaderAddr) + ExecutorAddr RegisterObjectSymbolTable, + ExecutorAddr DeregisterObjectSymbolTable) : MaterializationUnit( {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}), MOP(MOP), PlatformJDName(PlatformJDName), CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)), - DeferredAAs(std::move(DeferredAAs)), - PlatformBootstrap(PlatformBootstrap), + SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)), + MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap), PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib), DeregisterJITDylib(DeregisterJITDylib), - MachOHeaderAddr(MachOHeaderAddr) {} + RegisterObjectSymbolTable(RegisterObjectSymbolTable), + DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {} StringRef getName() const override { return "MachOPlatformCompleteBootstrap"; @@ -211,7 +158,7 @@ public: Linkage::Strong, Scope::Hidden, false, true); // Reserve space for the stolen actions, plus two extras. - G->allocActions().reserve(DeferredAAs.size() + 2); + G->allocActions().reserve(DeferredAAs.size() + 3); // 1. Bootstrap the platform support code. G->allocActions().push_back( @@ -227,7 +174,14 @@ public: cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( DeregisterJITDylib, MachOHeaderAddr))}); - // 3. Add the deferred actions to the graph. + // 3. Register deferred symbols. + G->allocActions().push_back( + {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( + RegisterObjectSymbolTable, MachOHeaderAddr, SymTab)), + cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( + DeregisterObjectSymbolTable, MachOHeaderAddr, SymTab))}); + + // 4. Add the deferred actions to the graph. std::move(DeferredAAs.begin(), DeferredAAs.end(), std::back_inserter(G->allocActions())); @@ -240,12 +194,15 @@ private: MachOPlatform &MOP; StringRef PlatformJDName; SymbolStringPtr CompleteBootstrapSymbol; + SymbolTableVector SymTab; shared::AllocActions DeferredAAs; + ExecutorAddr MachOHeaderAddr; ExecutorAddr PlatformBootstrap; ExecutorAddr PlatformShutdown; ExecutorAddr RegisterJITDylib; ExecutorAddr DeregisterJITDylib; - ExecutorAddr MachOHeaderAddr; + ExecutorAddr RegisterObjectSymbolTable; + ExecutorAddr DeregisterObjectSymbolTable; }; static StringRef ObjCRuntimeObjectSectionsData[] = { @@ -266,6 +223,33 @@ static StringRef ObjCRuntimeObjectSectionName = static StringRef ObjCImageInfoSymbolName = "__llvm_jitlink_macho_objc_imageinfo"; +struct ObjCImageInfoFlags { + uint16_t SwiftABIVersion; + uint16_t SwiftVersion; + bool HasCategoryClassProperties; + bool HasSignedObjCClassROs; + + static constexpr uint32_t SIGNED_CLASS_RO = (1 << 4); + static constexpr uint32_t HAS_CATEGORY_CLASS_PROPERTIES = (1 << 6); + + explicit ObjCImageInfoFlags(uint32_t RawFlags) { + HasSignedObjCClassROs = RawFlags & SIGNED_CLASS_RO; + HasCategoryClassProperties = RawFlags & HAS_CATEGORY_CLASS_PROPERTIES; + SwiftABIVersion = (RawFlags >> 8) & 0xFF; + SwiftVersion = (RawFlags >> 16) & 0xFFFF; + } + + uint32_t rawFlags() const { + uint32_t Result = 0; + if (HasCategoryClassProperties) + Result |= HAS_CATEGORY_CLASS_PROPERTIES; + if (HasSignedObjCClassROs) + Result |= SIGNED_CLASS_RO; + Result |= (SwiftABIVersion << 8); + Result |= (SwiftVersion << 16); + return Result; + } +}; } // end anonymous namespace namespace llvm { @@ -275,6 +259,7 @@ Expected<std::unique_ptr<MachOPlatform>> MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, + MachOHeaderMUBuilder BuildMachOHeaderMU, std::optional<SymbolAliasMap> RuntimeAliases) { // If the target is not supported then bail out immediately. @@ -305,8 +290,9 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, // Create the instance. Error Err = Error::success(); - auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform( - ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err)); + auto P = std::unique_ptr<MachOPlatform>( + new MachOPlatform(ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), + std::move(BuildMachOHeaderMU), Err)); if (Err) return std::move(Err); return std::move(P); @@ -315,6 +301,7 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, Expected<std::unique_ptr<MachOPlatform>> MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, const char *OrcRuntimePath, + MachOHeaderMUBuilder BuildMachOHeaderMU, std::optional<SymbolAliasMap> RuntimeAliases) { // Create a generator for the ORC runtime archive. @@ -325,12 +312,11 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, return Create(ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator), - std::move(RuntimeAliases)); + std::move(BuildMachOHeaderMU), std::move(RuntimeAliases)); } Error MachOPlatform::setupJITDylib(JITDylib &JD) { - if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>( - *this, MachOHeaderStartSymbol))) + if (auto Err = JD.define(BuildMachOHeaderMU(*this))) return Err; return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError(); @@ -419,11 +405,36 @@ bool MachOPlatform::supportedTarget(const Triple &TT) { } } +jitlink::Edge::Kind MachOPlatform::getPointerEdgeKind(jitlink::LinkGraph &G) { + switch (G.getTargetTriple().getArch()) { + case Triple::aarch64: + return jitlink::aarch64::Pointer64; + case Triple::x86_64: + return jitlink::x86_64::Pointer64; + default: + llvm_unreachable("Unsupported architecture"); + } +} + +MachOPlatform::MachOExecutorSymbolFlags +MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) { + MachOPlatform::MachOExecutorSymbolFlags Flags{}; + if (Sym.getLinkage() == jitlink::Linkage::Weak) + Flags |= MachOExecutorSymbolFlags::Weak; + + if (Sym.isCallable()) + Flags |= MachOExecutorSymbolFlags::Callable; + + return Flags; +} + MachOPlatform::MachOPlatform( ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, - std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) - : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) { + std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, + MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err) + : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer), + BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) { ErrorAsOutParameter _(&Err); ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this)); PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); @@ -442,11 +453,11 @@ MachOPlatform::MachOPlatform( // itself (to build the allocation actions that will call the registration // functions). Further complicating the situation (a) the graph containing // the registration functions is allowed to depend on other graphs (e.g. the - // graph containing the ORC runtime RTTI support) so we need to handle with - // an unknown set of dependencies during bootstrap, and (b) these graphs may + // graph containing the ORC runtime RTTI support) so we need to handle an + // unknown set of dependencies during bootstrap, and (b) these graphs may // be linked concurrently if the user has installed a concurrent dispatcher. // - // We satisfy these constraint by implementing a bootstrap phase during which + // We satisfy these constraints by implementing a bootstrap phase during which // allocation actions generated by MachOPlatform are appended to a list of // deferred allocation actions, rather than to the graphs themselves. At the // end of the bootstrap process the deferred actions are attached to a final @@ -486,8 +497,7 @@ MachOPlatform::MachOPlatform( // the support methods callable. The bootstrap is now complete. // Step (1) Add header materialization unit and request. - if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>( - *this, MachOHeaderStartSymbol)))) + if ((Err = PlatformJD.define(this->BuildMachOHeaderMU(*this)))) return; if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError())) return; @@ -498,6 +508,8 @@ MachOPlatform::MachOPlatform( SymbolLookupSet( {PlatformBootstrap.Name, PlatformShutdown.Name, RegisterJITDylib.Name, DeregisterJITDylib.Name, + RegisterObjectSymbolTable.Name, + DeregisterObjectSymbolTable.Name, RegisterObjectPlatformSections.Name, DeregisterObjectPlatformSections.Name, CreatePThreadKey.Name})) @@ -516,9 +528,11 @@ MachOPlatform::MachOPlatform( if ((Err = PlatformJD.define( std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>( *this, PlatformJD.getName(), BootstrapCompleteSymbol, - std::move(BI.DeferredAAs), PlatformBootstrap.Addr, + std::move(BI.SymTab), std::move(BI.DeferredAAs), + BI.MachOHeaderAddr, PlatformBootstrap.Addr, PlatformShutdown.Addr, RegisterJITDylib.Addr, - DeregisterJITDylib.Addr, BI.MachOHeaderAddr)))) + DeregisterJITDylib.Addr, RegisterObjectSymbolTable.Addr, + DeregisterObjectSymbolTable.Addr)))) return; if ((Err = ES.lookup(makeJITDylibSearchOrder( &PlatformJD, JITDylibLookupFlags::MatchAllSymbols), @@ -540,11 +554,11 @@ Error MachOPlatform::associateRuntimeSupportFunctions() { ES.wrapAsyncWithSPS<PushInitializersSPSSig>( this, &MachOPlatform::rt_pushInitializers); - using LookupSymbolSPSSig = - SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); - WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] = - ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, - &MachOPlatform::rt_lookupSymbol); + using PushSymbolsSPSSig = + SPSError(SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>); + WFs[ES.intern("___orc_rt_macho_push_symbols_tag")] = + ES.wrapAsyncWithSPS<PushSymbolsSPSSig>(this, + &MachOPlatform::rt_pushSymbols); return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); } @@ -665,11 +679,9 @@ void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult, pushInitializersLoop(std::move(SendResult), JD); } -void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, - ExecutorAddr Handle, StringRef SymbolName) { - LLVM_DEBUG({ - dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle << "\")\n"; - }); +void MachOPlatform::rt_pushSymbols( + PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle, + const std::vector<std::pair<StringRef, bool>> &SymbolNames) { JITDylib *JD = nullptr; @@ -679,39 +691,37 @@ void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, if (I != HeaderAddrToJITDylib.end()) JD = I->second; } + LLVM_DEBUG({ + dbgs() << "MachOPlatform::rt_pushSymbols("; + if (JD) + dbgs() << "\"" << JD->getName() << "\", [ "; + else + dbgs() << "<invalid handle " << Handle << ">, [ "; + for (auto &Name : SymbolNames) + dbgs() << "\"" << Name.first << "\" "; + dbgs() << "])\n"; + }); if (!JD) { - LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n"); SendResult(make_error<StringError>("No JITDylib associated with handle " + formatv("{0:x}", Handle), inconvertibleErrorCode())); return; } - // Use functor class to work around XL build compiler issue on AIX. - class RtLookupNotifyComplete { - public: - RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) - : SendResult(std::move(SendResult)) {} - void operator()(Expected<SymbolMap> Result) { - if (Result) { - assert(Result->size() == 1 && "Unexpected result map count"); - SendResult(Result->begin()->second.getAddress()); - } else { - SendResult(Result.takeError()); - } - } - - private: - SendSymbolAddressFn SendResult; - }; + SymbolLookupSet LS; + for (auto &[Name, Required] : SymbolNames) + LS.add(ES.intern(Name), Required + ? SymbolLookupFlags::RequiredSymbol + : SymbolLookupFlags::WeaklyReferencedSymbol); - // FIXME: Proper mangling. - auto MangledName = ("_" + SymbolName).str(); ES.lookup( LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, - SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready, - RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); + std::move(LS), SymbolState::Ready, + [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable { + SendResult(Result.takeError()); + }, + NoDependenciesToRegister); } Expected<uint64_t> MachOPlatform::createPThreadKey() { @@ -781,6 +791,18 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( return fixTLVSectionsAndEdges(G, JD); }); + // Add symbol table prepare and register passes: These will add strings for + // all symbols to the c-strings section, and build a symbol table registration + // call. + auto JITSymTabInfo = std::make_shared<JITSymTabVector>(); + Config.PostPrunePasses.push_back([this, JITSymTabInfo](LinkGraph &G) { + return prepareSymbolTableRegistration(G, *JITSymTabInfo); + }); + Config.PostFixupPasses.push_back([this, &MR, JITSymTabInfo, + InBootstrapPhase](LinkGraph &G) { + return addSymbolTableRegistration(G, MR, *JITSymTabInfo, InBootstrapPhase); + }); + // Add a pass to register the final addresses of any special sections in the // object with the runtime. Config.PostAllocationPasses.push_back( @@ -826,6 +848,9 @@ Error MachOPlatform::MachOPlatformPlugin:: {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr}, {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr}, {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr}, + {*MP.RegisterObjectSymbolTable.Name, &MP.RegisterObjectSymbolTable.Addr}, + {*MP.DeregisterObjectSymbolTable.Name, + &MP.DeregisterObjectSymbolTable.Addr}, {*MP.RegisterObjectPlatformSections.Name, &MP.RegisterObjectPlatformSections.Addr}, {*MP.DeregisterObjectPlatformSections.Name, @@ -1029,15 +1054,19 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( " does not match first registered version", inconvertibleErrorCode()); if (ObjCImageInfoItr->second.Flags != Flags) - return make_error<StringError>("ObjC flags in " + G.getName() + - " do not match first registered flags", - inconvertibleErrorCode()); + if (Error E = mergeImageInfoFlags(G, MR, ObjCImageInfoItr->second, Flags)) + return E; // __objc_imageinfo is valid. Delete the block. for (auto *S : ObjCImageInfo->symbols()) G.removeDefinedSymbol(*S); G.removeBlock(ObjCImageInfoBlock); } else { + LLVM_DEBUG({ + dbgs() << "MachOPlatform: Registered __objc_imageinfo for " + << MR.getTargetJITDylib().getName() << " in " << G.getName() + << "; flags = " << formatv("{0:x4}", Flags) << "\n"; + }); // We haven't registered an __objc_imageinfo section yet. Register and // move on. The section should already be marked no-dead-strip. G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName, @@ -1047,12 +1076,66 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName), JITSymbolFlags()}})) return Err; - ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags}; + ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags, false}; } return Error::success(); } +Error MachOPlatform::MachOPlatformPlugin::mergeImageInfoFlags( + jitlink::LinkGraph &G, MaterializationResponsibility &MR, + ObjCImageInfo &Info, uint32_t NewFlags) { + if (Info.Flags == NewFlags) + return Error::success(); + + ObjCImageInfoFlags Old(Info.Flags); + ObjCImageInfoFlags New(NewFlags); + + // Check for incompatible flags. + if (Old.SwiftABIVersion && New.SwiftABIVersion && + Old.SwiftABIVersion != New.SwiftABIVersion) + return make_error<StringError>("Swift ABI version in " + G.getName() + + " does not match first registered flags", + inconvertibleErrorCode()); + + if (Old.HasCategoryClassProperties != New.HasCategoryClassProperties) + return make_error<StringError>("ObjC category class property support in " + + G.getName() + + " does not match first registered flags", + inconvertibleErrorCode()); + if (Old.HasSignedObjCClassROs != New.HasSignedObjCClassROs) + return make_error<StringError>("ObjC class_ro_t pointer signing in " + + G.getName() + + " does not match first registered flags", + inconvertibleErrorCode()); + + // If we cannot change the flags, ignore any remaining differences. Adding + // Swift or changing its version are unlikely to cause problems in practice. + if (Info.Finalized) + return Error::success(); + + // Use the minimum Swift version. + if (Old.SwiftVersion && New.SwiftVersion) + New.SwiftVersion = std::min(Old.SwiftVersion, New.SwiftVersion); + else if (Old.SwiftVersion) + New.SwiftVersion = Old.SwiftVersion; + // Add a Swift ABI version if it was pure objc before. + if (!New.SwiftABIVersion) + New.SwiftABIVersion = Old.SwiftABIVersion; + + LLVM_DEBUG({ + dbgs() << "MachOPlatform: Merging __objc_imageinfo flags for " + << MR.getTargetJITDylib().getName() << " (was " + << formatv("{0:x4}", Old.rawFlags()) << ")" + << " with " << G.getName() << " (" << formatv("{0:x4}", NewFlags) + << ")" + << " -> " << formatv("{0:x4}", New.rawFlags()) << "\n"; + }); + + Info.Flags = New.rawFlags(); + return Error::success(); +} + Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( jitlink::LinkGraph &G, JITDylib &JD) { @@ -1250,15 +1333,6 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( UI->CompactUnwindSection); if (!MachOPlatformSecs.empty() || UnwindInfo) { - ExecutorAddr HeaderAddr; - { - std::lock_guard<std::mutex> Lock(MP.PlatformMutex); - auto I = MP.JITDylibToHeaderAddr.find(&JD); - assert(I != MP.JITDylibToHeaderAddr.end() && - "Missing header for JITDylib"); - HeaderAddr = I->second; - } - // Dump the scraped inits. LLVM_DEBUG({ dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; @@ -1276,6 +1350,15 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( ? G.allocActions() : MP.Bootstrap.load()->DeferredAAs; + ExecutorAddr HeaderAddr; + { + std::lock_guard<std::mutex> Lock(MP.PlatformMutex); + auto I = MP.JITDylibToHeaderAddr.find(&JD); + assert(I != MP.JITDylibToHeaderAddr.end() && + "No header registered for JD"); + assert(I->second && "Null header registered for JD"); + HeaderAddr = I->second; + } allocActions.push_back( {cantFail( WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( @@ -1374,17 +1457,7 @@ Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( strcpy(SD.Sec.segname, "__DATA"); SD.Sec.size = 8; SD.AddFixups = [&](size_t RecordOffset) { - jitlink::Edge::Kind PointerEdge = jitlink::Edge::Invalid; - switch (G.getTargetTriple().getArch()) { - case Triple::aarch64: - PointerEdge = jitlink::aarch64::Pointer64; - break; - case Triple::x86_64: - PointerEdge = jitlink::x86_64::Pointer64; - break; - default: - llvm_unreachable("Unsupported architecture"); - } + auto PointerEdge = getPointerEdgeKind(G); // Look for an existing __objc_imageinfo symbol. jitlink::Symbol *ObjCImageInfoSym = nullptr; @@ -1403,6 +1476,24 @@ Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( for (auto *Sym : G.defined_symbols()) if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) { ObjCImageInfoSym = Sym; + std::optional<uint32_t> Flags; + { + std::lock_guard<std::mutex> Lock(PluginMutex); + auto It = ObjCImageInfos.find(&MR.getTargetJITDylib()); + if (It != ObjCImageInfos.end()) { + It->second.Finalized = true; + Flags = It->second.Flags; + } + } + + if (Flags) { + // We own the definition of __objc_image_info; write the final + // merged flags value. + auto Content = Sym->getBlock().getMutableContent(G); + assert(Content.size() == 8 && + "__objc_image_info size should have been verified already"); + support::endian::write32(&Content[4], *Flags, G.getEndianness()); + } break; } if (!ObjCImageInfoSym) @@ -1460,7 +1551,7 @@ Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( auto SecContent = SecBlock.getAlreadyMutableContent(); char *P = SecContent.data(); auto WriteMachOStruct = [&](auto S) { - if (G.getEndianness() != support::endian::system_endianness()) + if (G.getEndianness() != llvm::endianness::native) MachO::swapStruct(S); memcpy(P, &S, sizeof(S)); P += sizeof(S); @@ -1492,5 +1583,179 @@ Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( return Error::success(); } +Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration( + jitlink::LinkGraph &G, JITSymTabVector &JITSymTabInfo) { + + auto *CStringSec = G.findSectionByName(MachOCStringSectionName); + if (!CStringSec) + CStringSec = &G.createSection(MachOCStringSectionName, + MemProt::Read | MemProt::Exec); + + // Make a map of existing strings so that we can re-use them: + DenseMap<StringRef, jitlink::Symbol *> ExistingStrings; + for (auto *Sym : CStringSec->symbols()) { + + // The LinkGraph builder should have created single strings blocks, and all + // plugins should have maintained this invariant. + auto Content = Sym->getBlock().getContent(); + ExistingStrings.insert( + std::make_pair(StringRef(Content.data(), Content.size()), Sym)); + } + + // Add all symbol names to the string section, and record the symbols for + // those names. + { + SmallVector<jitlink::Symbol *> SymsToProcess; + for (auto *Sym : G.defined_symbols()) + SymsToProcess.push_back(Sym); + + for (auto *Sym : SymsToProcess) { + if (!Sym->hasName()) + continue; + + auto I = ExistingStrings.find(Sym->getName()); + if (I == ExistingStrings.end()) { + auto &NameBlock = G.createMutableContentBlock( + *CStringSec, G.allocateCString(Sym->getName()), orc::ExecutorAddr(), + 1, 0); + auto &SymbolNameSym = G.addAnonymousSymbol( + NameBlock, 0, NameBlock.getSize(), false, true); + JITSymTabInfo.push_back({Sym, &SymbolNameSym}); + } else + JITSymTabInfo.push_back({Sym, I->second}); + } + } + + return Error::success(); +} + +Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration( + jitlink::LinkGraph &G, MaterializationResponsibility &MR, + JITSymTabVector &JITSymTabInfo, bool InBootstrapPhase) { + + ExecutorAddr HeaderAddr; + { + std::lock_guard<std::mutex> Lock(MP.PlatformMutex); + auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib()); + assert(I != MP.JITDylibToHeaderAddr.end() && "No header registered for JD"); + assert(I->second && "Null header registered for JD"); + HeaderAddr = I->second; + } + + SymbolTableVector LocalSymTab; + auto &SymTab = LLVM_LIKELY(!InBootstrapPhase) ? LocalSymTab + : MP.Bootstrap.load()->SymTab; + for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo) + SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(), + flagsForSymbol(*OriginalSymbol)}); + + // Bail out if we're in the bootstrap phase -- registration of thees symbols + // will be attached to the bootstrap graph. + if (LLVM_UNLIKELY(InBootstrapPhase)) + return Error::success(); + + shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase) + ? G.allocActions() + : MP.Bootstrap.load()->DeferredAAs; + allocActions.push_back( + {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( + MP.RegisterObjectSymbolTable.Addr, HeaderAddr, SymTab)), + cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( + MP.DeregisterObjectSymbolTable.Addr, HeaderAddr, SymTab))}); + + return Error::success(); +} + +template <typename MachOTraits> +jitlink::Block &createTrivialHeaderBlock(MachOPlatform &MOP, + jitlink::LinkGraph &G, + jitlink::Section &HeaderSection) { + auto HdrInfo = + getMachOHeaderInfoFromTriple(MOP.getExecutionSession().getTargetTriple()); + MachOBuilder<MachOTraits> B(HdrInfo.PageSize); + + B.Header.filetype = MachO::MH_DYLIB; + B.Header.cputype = HdrInfo.CPUType; + B.Header.cpusubtype = HdrInfo.CPUSubType; + + auto HeaderContent = G.allocateBuffer(B.layout()); + B.write(HeaderContent); + + return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8, + 0); +} + +SimpleMachOHeaderMU::SimpleMachOHeaderMU(MachOPlatform &MOP, + SymbolStringPtr HeaderStartSymbol) + : MaterializationUnit( + createHeaderInterface(MOP, std::move(HeaderStartSymbol))), + MOP(MOP) {} + +void SimpleMachOHeaderMU::materialize( + std::unique_ptr<MaterializationResponsibility> R) { + auto G = createPlatformGraph(MOP, "<MachOHeaderMU>"); + addMachOHeader(R->getTargetJITDylib(), *G, R->getInitializerSymbol()); + MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); +} + +void SimpleMachOHeaderMU::discard(const JITDylib &JD, + const SymbolStringPtr &Sym) {} + +void SimpleMachOHeaderMU::addMachOHeader( + JITDylib &JD, jitlink::LinkGraph &G, + const SymbolStringPtr &InitializerSymbol) { + auto &HeaderSection = G.createSection("__header", MemProt::Read); + auto &HeaderBlock = createHeaderBlock(JD, G, HeaderSection); + + // Init symbol is header-start symbol. + G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, HeaderBlock.getSize(), + jitlink::Linkage::Strong, jitlink::Scope::Default, false, + true); + for (auto &HS : AdditionalHeaderSymbols) + G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(), + jitlink::Linkage::Strong, jitlink::Scope::Default, false, + true); +} + +jitlink::Block & +SimpleMachOHeaderMU::createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G, + jitlink::Section &HeaderSection) { + switch (MOP.getExecutionSession().getTargetTriple().getArch()) { + case Triple::aarch64: + case Triple::x86_64: + return createTrivialHeaderBlock<MachO64LE>(MOP, G, HeaderSection); + default: + llvm_unreachable("Unsupported architecture"); + } +} + +MaterializationUnit::Interface SimpleMachOHeaderMU::createHeaderInterface( + MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) { + SymbolFlagsMap HeaderSymbolFlags; + + HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; + for (auto &HS : AdditionalHeaderSymbols) + HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] = + JITSymbolFlags::Exported; + + return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), + HeaderStartSymbol); +} + +MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT) { + switch (TT.getArch()) { + case Triple::aarch64: + return {/* PageSize = */ 16 * 1024, + /* CPUType = */ MachO::CPU_TYPE_ARM64, + /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL}; + case Triple::x86_64: + return {/* PageSize = */ 4 * 1024, + /* CPUType = */ MachO::CPU_TYPE_X86_64, + /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL}; + default: + llvm_unreachable("Unrecognized architecture"); + } +} + } // End namespace orc. } // End namespace llvm. |
