Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
35266 views
//===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"910#include "llvm/BinaryFormat/ELF.h"11#include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"12#include "llvm/ExecutionEngine/JITLink/aarch64.h"13#include "llvm/ExecutionEngine/JITLink/ppc64.h"14#include "llvm/ExecutionEngine/JITLink/x86_64.h"15#include "llvm/ExecutionEngine/Orc/DebugUtils.h"16#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"17#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"18#include "llvm/Support/BinaryByteStream.h"19#include "llvm/Support/Debug.h"20#include <optional>2122#define DEBUG_TYPE "orc"2324using namespace llvm;25using namespace llvm::orc;26using namespace llvm::orc::shared;2728namespace {2930class DSOHandleMaterializationUnit : public MaterializationUnit {31public:32DSOHandleMaterializationUnit(ELFNixPlatform &ENP,33const SymbolStringPtr &DSOHandleSymbol)34: MaterializationUnit(35createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),36ENP(ENP) {}3738StringRef getName() const override { return "DSOHandleMU"; }3940void materialize(std::unique_ptr<MaterializationResponsibility> R) override {41unsigned PointerSize;42llvm::endianness Endianness;43jitlink::Edge::Kind EdgeKind;44const auto &TT = ENP.getExecutionSession().getTargetTriple();4546switch (TT.getArch()) {47case Triple::x86_64:48PointerSize = 8;49Endianness = llvm::endianness::little;50EdgeKind = jitlink::x86_64::Pointer64;51break;52case Triple::aarch64:53PointerSize = 8;54Endianness = llvm::endianness::little;55EdgeKind = jitlink::aarch64::Pointer64;56break;57case Triple::ppc64:58PointerSize = 8;59Endianness = llvm::endianness::big;60EdgeKind = jitlink::ppc64::Pointer64;61break;62case Triple::ppc64le:63PointerSize = 8;64Endianness = llvm::endianness::little;65EdgeKind = jitlink::ppc64::Pointer64;66break;67default:68llvm_unreachable("Unrecognized architecture");69}7071// void *__dso_handle = &__dso_handle;72auto G = std::make_unique<jitlink::LinkGraph>(73"<DSOHandleMU>", TT, PointerSize, Endianness,74jitlink::getGenericEdgeKindName);75auto &DSOHandleSection =76G->createSection(".data.__dso_handle", MemProt::Read);77auto &DSOHandleBlock = G->createContentBlock(78DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(),798, 0);80auto &DSOHandleSymbol = G->addDefinedSymbol(81DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),82jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);83DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);8485ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));86}8788void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}8990private:91static MaterializationUnit::Interface92createDSOHandleSectionInterface(ELFNixPlatform &ENP,93const SymbolStringPtr &DSOHandleSymbol) {94SymbolFlagsMap SymbolFlags;95SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;96return MaterializationUnit::Interface(std::move(SymbolFlags),97DSOHandleSymbol);98}99100ArrayRef<char> getDSOHandleContent(size_t PointerSize) {101static const char Content[8] = {0};102assert(PointerSize <= sizeof Content);103return {Content, PointerSize};104}105106ELFNixPlatform &ENP;107};108109} // end anonymous namespace110111namespace llvm {112namespace orc {113114Expected<std::unique_ptr<ELFNixPlatform>> ELFNixPlatform::Create(115ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,116JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,117std::optional<SymbolAliasMap> RuntimeAliases) {118119// If the target is not supported then bail out immediately.120if (!supportedTarget(ES.getTargetTriple()))121return make_error<StringError>("Unsupported ELFNixPlatform triple: " +122ES.getTargetTriple().str(),123inconvertibleErrorCode());124125auto &EPC = ES.getExecutorProcessControl();126127// Create default aliases if the caller didn't supply any.128if (!RuntimeAliases) {129auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD);130if (!StandardRuntimeAliases)131return StandardRuntimeAliases.takeError();132RuntimeAliases = std::move(*StandardRuntimeAliases);133}134135// Define the aliases.136if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))137return std::move(Err);138139// Add JIT-dispatch function support symbols.140if (auto Err = PlatformJD.define(141absoluteSymbols({{ES.intern("__orc_rt_jit_dispatch"),142{EPC.getJITDispatchInfo().JITDispatchFunction,143JITSymbolFlags::Exported}},144{ES.intern("__orc_rt_jit_dispatch_ctx"),145{EPC.getJITDispatchInfo().JITDispatchContext,146JITSymbolFlags::Exported}}})))147return std::move(Err);148149// Create the instance.150Error Err = Error::success();151auto P = std::unique_ptr<ELFNixPlatform>(new ELFNixPlatform(152ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));153if (Err)154return std::move(Err);155return std::move(P);156}157158Expected<std::unique_ptr<ELFNixPlatform>>159ELFNixPlatform::Create(ExecutionSession &ES,160ObjectLinkingLayer &ObjLinkingLayer,161JITDylib &PlatformJD, const char *OrcRuntimePath,162std::optional<SymbolAliasMap> RuntimeAliases) {163164// Create a generator for the ORC runtime archive.165auto OrcRuntimeArchiveGenerator =166StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);167if (!OrcRuntimeArchiveGenerator)168return OrcRuntimeArchiveGenerator.takeError();169170return Create(ES, ObjLinkingLayer, PlatformJD,171std::move(*OrcRuntimeArchiveGenerator),172std::move(RuntimeAliases));173}174175Error ELFNixPlatform::setupJITDylib(JITDylib &JD) {176return JD.define(177std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol));178}179180Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) {181return Error::success();182}183184Error ELFNixPlatform::notifyAdding(ResourceTracker &RT,185const MaterializationUnit &MU) {186auto &JD = RT.getJITDylib();187const auto &InitSym = MU.getInitializerSymbol();188if (!InitSym)189return Error::success();190191RegisteredInitSymbols[&JD].add(InitSym,192SymbolLookupFlags::WeaklyReferencedSymbol);193LLVM_DEBUG({194dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym195<< " for MU " << MU.getName() << "\n";196});197return Error::success();198}199200Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) {201llvm_unreachable("Not supported yet");202}203204static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,205ArrayRef<std::pair<const char *, const char *>> AL) {206for (auto &KV : AL) {207auto AliasName = ES.intern(KV.first);208assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");209Aliases[std::move(AliasName)] = {ES.intern(KV.second),210JITSymbolFlags::Exported};211}212}213214Expected<SymbolAliasMap>215ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES,216JITDylib &PlatformJD) {217SymbolAliasMap Aliases;218addAliases(ES, Aliases, requiredCXXAliases());219addAliases(ES, Aliases, standardRuntimeUtilityAliases());220return Aliases;221}222223ArrayRef<std::pair<const char *, const char *>>224ELFNixPlatform::requiredCXXAliases() {225static const std::pair<const char *, const char *> RequiredCXXAliases[] = {226{"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},227{"atexit", "__orc_rt_elfnix_atexit"}};228229return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);230}231232ArrayRef<std::pair<const char *, const char *>>233ELFNixPlatform::standardRuntimeUtilityAliases() {234static const std::pair<const char *, const char *>235StandardRuntimeUtilityAliases[] = {236{"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},237{"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"},238{"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"},239{"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"},240{"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"},241{"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};242243return ArrayRef<std::pair<const char *, const char *>>(244StandardRuntimeUtilityAliases);245}246247bool ELFNixPlatform::supportedTarget(const Triple &TT) {248switch (TT.getArch()) {249case Triple::x86_64:250case Triple::aarch64:251// FIXME: jitlink for ppc64 hasn't been well tested, leave it unsupported252// right now.253case Triple::ppc64le:254return true;255default:256return false;257}258}259260ELFNixPlatform::ELFNixPlatform(261ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,262JITDylib &PlatformJD,263std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)264: ES(ES), ObjLinkingLayer(ObjLinkingLayer),265DSOHandleSymbol(ES.intern("__dso_handle")) {266ErrorAsOutParameter _(&Err);267268ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));269270PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));271272// PlatformJD hasn't been 'set-up' by the platform yet (since we're creating273// the platform now), so set it up.274if (auto E2 = setupJITDylib(PlatformJD)) {275Err = std::move(E2);276return;277}278279RegisteredInitSymbols[&PlatformJD].add(280DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);281282// Associate wrapper function tags with JIT-side function implementations.283if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {284Err = std::move(E2);285return;286}287288// Lookup addresses of runtime functions callable by the platform,289// call the platform bootstrap function to initialize the platform-state290// object in the executor.291if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) {292Err = std::move(E2);293return;294}295}296297Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {298ExecutionSession::JITDispatchHandlerAssociationMap WFs;299300using GetInitializersSPSSig =301SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString);302WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] =303ES.wrapAsyncWithSPS<GetInitializersSPSSig>(304this, &ELFNixPlatform::rt_getInitializers);305306using GetDeinitializersSPSSig =307SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr);308WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] =309ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(310this, &ELFNixPlatform::rt_getDeinitializers);311312using LookupSymbolSPSSig =313SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);314WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] =315ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,316&ELFNixPlatform::rt_lookupSymbol);317318return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));319}320321void ELFNixPlatform::getInitializersBuildSequencePhase(322SendInitializerSequenceFn SendResult, JITDylib &JD,323std::vector<JITDylibSP> DFSLinkOrder) {324ELFNixJITDylibInitializerSequence FullInitSeq;325{326std::lock_guard<std::mutex> Lock(PlatformMutex);327for (auto &InitJD : reverse(DFSLinkOrder)) {328LLVM_DEBUG({329dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName()330<< "\" to sequence\n";331});332auto ISItr = InitSeqs.find(InitJD.get());333if (ISItr != InitSeqs.end()) {334FullInitSeq.emplace_back(std::move(ISItr->second));335InitSeqs.erase(ISItr);336}337}338}339340SendResult(std::move(FullInitSeq));341}342343void ELFNixPlatform::getInitializersLookupPhase(344SendInitializerSequenceFn SendResult, JITDylib &JD) {345346auto DFSLinkOrder = JD.getDFSLinkOrder();347if (!DFSLinkOrder) {348SendResult(DFSLinkOrder.takeError());349return;350}351352DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;353ES.runSessionLocked([&]() {354for (auto &InitJD : *DFSLinkOrder) {355auto RISItr = RegisteredInitSymbols.find(InitJD.get());356if (RISItr != RegisteredInitSymbols.end()) {357NewInitSymbols[InitJD.get()] = std::move(RISItr->second);358RegisteredInitSymbols.erase(RISItr);359}360}361});362363// If there are no further init symbols to look up then move on to the next364// phase.365if (NewInitSymbols.empty()) {366getInitializersBuildSequencePhase(std::move(SendResult), JD,367std::move(*DFSLinkOrder));368return;369}370371// Otherwise issue a lookup and re-run this phase when it completes.372lookupInitSymbolsAsync(373[this, SendResult = std::move(SendResult), &JD](Error Err) mutable {374if (Err)375SendResult(std::move(Err));376else377getInitializersLookupPhase(std::move(SendResult), JD);378},379ES, std::move(NewInitSymbols));380}381382void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,383StringRef JDName) {384LLVM_DEBUG({385dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";386});387388JITDylib *JD = ES.getJITDylibByName(JDName);389if (!JD) {390LLVM_DEBUG({391dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n";392});393SendResult(make_error<StringError>("No JITDylib named " + JDName,394inconvertibleErrorCode()));395return;396}397398getInitializersLookupPhase(std::move(SendResult), *JD);399}400401void ELFNixPlatform::rt_getDeinitializers(402SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) {403LLVM_DEBUG({404dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" << Handle << "\")\n";405});406407JITDylib *JD = nullptr;408409{410std::lock_guard<std::mutex> Lock(PlatformMutex);411auto I = HandleAddrToJITDylib.find(Handle);412if (I != HandleAddrToJITDylib.end())413JD = I->second;414}415416if (!JD) {417LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n");418SendResult(make_error<StringError>("No JITDylib associated with handle " +419formatv("{0:x}", Handle),420inconvertibleErrorCode()));421return;422}423424SendResult(ELFNixJITDylibDeinitializerSequence());425}426427void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,428ExecutorAddr Handle,429StringRef SymbolName) {430LLVM_DEBUG({431dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n";432});433434JITDylib *JD = nullptr;435436{437std::lock_guard<std::mutex> Lock(PlatformMutex);438auto I = HandleAddrToJITDylib.find(Handle);439if (I != HandleAddrToJITDylib.end())440JD = I->second;441}442443if (!JD) {444LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n");445SendResult(make_error<StringError>("No JITDylib associated with handle " +446formatv("{0:x}", Handle),447inconvertibleErrorCode()));448return;449}450451// Use functor class to work around XL build compiler issue on AIX.452class RtLookupNotifyComplete {453public:454RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)455: SendResult(std::move(SendResult)) {}456void operator()(Expected<SymbolMap> Result) {457if (Result) {458assert(Result->size() == 1 && "Unexpected result map count");459SendResult(Result->begin()->second.getAddress());460} else {461SendResult(Result.takeError());462}463}464465private:466SendSymbolAddressFn SendResult;467};468469ES.lookup(470LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},471SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,472RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);473}474475Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) {476477std::pair<const char *, ExecutorAddr *> Symbols[] = {478{"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap},479{"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown},480{"__orc_rt_elfnix_register_object_sections",481&orc_rt_elfnix_register_object_sections},482{"__orc_rt_elfnix_create_pthread_key",483&orc_rt_elfnix_create_pthread_key}};484485SymbolLookupSet RuntimeSymbols;486std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord;487for (const auto &KV : Symbols) {488auto Name = ES.intern(KV.first);489RuntimeSymbols.add(Name);490AddrsToRecord.push_back({std::move(Name), KV.second});491}492493auto RuntimeSymbolAddrs = ES.lookup(494{{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);495if (!RuntimeSymbolAddrs)496return RuntimeSymbolAddrs.takeError();497498for (const auto &KV : AddrsToRecord) {499auto &Name = KV.first;500assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?");501*KV.second = (*RuntimeSymbolAddrs)[Name].getAddress();502}503504auto PJDDSOHandle = ES.lookup(505{{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol);506if (!PJDDSOHandle)507return PJDDSOHandle.takeError();508509if (auto Err = ES.callSPSWrapper<void(uint64_t)>(510orc_rt_elfnix_platform_bootstrap,511PJDDSOHandle->getAddress().getValue()))512return Err;513514// FIXME: Ordering is fuzzy here. We're probably best off saying515// "behavior is undefined if code that uses the runtime is added before516// the platform constructor returns", then move all this to the constructor.517RuntimeBootstrapped = true;518std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs;519{520std::lock_guard<std::mutex> Lock(PlatformMutex);521DeferredPOSRs = std::move(BootstrapPOSRs);522}523524for (auto &D : DeferredPOSRs)525if (auto Err = registerPerObjectSections(D))526return Err;527528return Error::success();529}530531Error ELFNixPlatform::registerInitInfo(532JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {533534std::unique_lock<std::mutex> Lock(PlatformMutex);535536ELFNixJITDylibInitializers *InitSeq = nullptr;537{538auto I = InitSeqs.find(&JD);539if (I == InitSeqs.end()) {540// If there's no init sequence entry yet then we need to look up the541// header symbol to force creation of one.542Lock.unlock();543544auto SearchOrder =545JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });546if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError())547return Err;548549Lock.lock();550I = InitSeqs.find(&JD);551assert(I != InitSeqs.end() &&552"Entry missing after header symbol lookup?");553}554InitSeq = &I->second;555}556557for (auto *Sec : InitSections) {558// FIXME: Avoid copy here.559jitlink::SectionRange R(*Sec);560InitSeq->InitSections[Sec->getName()].push_back(R.getRange());561}562563return Error::success();564}565566Error ELFNixPlatform::registerPerObjectSections(567const ELFPerObjectSectionsToRegister &POSR) {568569if (!orc_rt_elfnix_register_object_sections)570return make_error<StringError>("Attempting to register per-object "571"sections, but runtime support has not "572"been loaded yet",573inconvertibleErrorCode());574575Error ErrResult = Error::success();576if (auto Err = ES.callSPSWrapper<shared::SPSError(577SPSELFPerObjectSectionsToRegister)>(578orc_rt_elfnix_register_object_sections, ErrResult, POSR))579return Err;580return ErrResult;581}582583Expected<uint64_t> ELFNixPlatform::createPThreadKey() {584if (!orc_rt_elfnix_create_pthread_key)585return make_error<StringError>(586"Attempting to create pthread key in target, but runtime support has "587"not been loaded yet",588inconvertibleErrorCode());589590Expected<uint64_t> Result(0);591if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(592orc_rt_elfnix_create_pthread_key, Result))593return std::move(Err);594return Result;595}596597void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(598MaterializationResponsibility &MR, jitlink::LinkGraph &LG,599jitlink::PassConfiguration &Config) {600601// If the initializer symbol is the __dso_handle symbol then just add602// the DSO handle support passes.603if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) {604addDSOHandleSupportPasses(MR, Config);605// The DSOHandle materialization unit doesn't require any other606// support, so we can bail out early.607return;608}609610// If the object contains initializers then add passes to record them.611if (MR.getInitializerSymbol())612addInitializerSupportPasses(MR, Config);613614// Add passes for eh-frame and TLV support.615addEHAndTLVSupportPasses(MR, Config);616}617618ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap619ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies(620MaterializationResponsibility &MR) {621std::lock_guard<std::mutex> Lock(PluginMutex);622auto I = InitSymbolDeps.find(&MR);623if (I != InitSymbolDeps.end()) {624SyntheticSymbolDependenciesMap Result;625Result[MR.getInitializerSymbol()] = std::move(I->second);626InitSymbolDeps.erase(&MR);627return Result;628}629return SyntheticSymbolDependenciesMap();630}631632void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses(633MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {634635/// Preserve init sections.636Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {637if (auto Err = preserveInitSections(G, MR))638return Err;639return Error::success();640});641642Config.PostFixupPasses.push_back(643[this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {644return registerInitSections(G, JD);645});646}647648void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(649MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {650651Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](652jitlink::LinkGraph &G) -> Error {653auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {654return Sym->getName() == *MP.DSOHandleSymbol;655});656assert(I != G.defined_symbols().end() && "Missing DSO handle symbol");657{658std::lock_guard<std::mutex> Lock(MP.PlatformMutex);659auto HandleAddr = (*I)->getAddress();660MP.HandleAddrToJITDylib[HandleAddr] = &JD;661assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");662MP.InitSeqs.insert(std::make_pair(663&JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr)));664}665return Error::success();666});667}668669void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(670MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {671672// Insert TLV lowering at the start of the PostPrunePasses, since we want673// it to run before GOT/PLT lowering.674675// TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build676// pass has done. Because the TLS descriptor need to be allocate in GOT.677Config.PostPrunePasses.push_back(678[this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {679return fixTLVSectionsAndEdges(G, JD);680});681682// Add a pass to register the final addresses of the eh-frame and TLV sections683// with the runtime.684Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {685ELFPerObjectSectionsToRegister POSR;686687if (auto *EHFrameSection = G.findSectionByName(ELFEHFrameSectionName)) {688jitlink::SectionRange R(*EHFrameSection);689if (!R.empty())690POSR.EHFrameSection = R.getRange();691}692693// Get a pointer to the thread data section if there is one. It will be used694// below.695jitlink::Section *ThreadDataSection =696G.findSectionByName(ELFThreadDataSectionName);697698// Handle thread BSS section if there is one.699if (auto *ThreadBSSSection = G.findSectionByName(ELFThreadBSSSectionName)) {700// If there's already a thread data section in this graph then merge the701// thread BSS section content into it, otherwise just treat the thread702// BSS section as the thread data section.703if (ThreadDataSection)704G.mergeSections(*ThreadDataSection, *ThreadBSSSection);705else706ThreadDataSection = ThreadBSSSection;707}708709// Having merged thread BSS (if present) and thread data (if present),710// record the resulting section range.711if (ThreadDataSection) {712jitlink::SectionRange R(*ThreadDataSection);713if (!R.empty())714POSR.ThreadDataSection = R.getRange();715}716717if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {718719// If we're still bootstrapping the runtime then just record this720// frame for now.721if (!MP.RuntimeBootstrapped) {722std::lock_guard<std::mutex> Lock(MP.PlatformMutex);723MP.BootstrapPOSRs.push_back(POSR);724return Error::success();725}726727// Otherwise register it immediately.728if (auto Err = MP.registerPerObjectSections(POSR))729return Err;730}731732return Error::success();733});734}735736Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(737jitlink::LinkGraph &G, MaterializationResponsibility &MR) {738739JITLinkSymbolSet InitSectionSymbols;740for (auto &InitSection : G.sections()) {741// Skip non-init sections.742if (!isELFInitializerSection(InitSection.getName()))743continue;744745// Make a pass over live symbols in the section: those blocks are already746// preserved.747DenseSet<jitlink::Block *> AlreadyLiveBlocks;748for (auto &Sym : InitSection.symbols()) {749auto &B = Sym->getBlock();750if (Sym->isLive() && Sym->getOffset() == 0 &&751Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {752InitSectionSymbols.insert(Sym);753AlreadyLiveBlocks.insert(&B);754}755}756757// Add anonymous symbols to preserve any not-already-preserved blocks.758for (auto *B : InitSection.blocks())759if (!AlreadyLiveBlocks.count(B))760InitSectionSymbols.insert(761&G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));762}763764if (!InitSectionSymbols.empty()) {765std::lock_guard<std::mutex> Lock(PluginMutex);766InitSymbolDeps[&MR] = std::move(InitSectionSymbols);767}768769return Error::success();770}771772Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(773jitlink::LinkGraph &G, JITDylib &JD) {774775SmallVector<jitlink::Section *> InitSections;776777LLVM_DEBUG(dbgs() << "ELFNixPlatform::registerInitSections\n");778779for (auto &Sec : G.sections()) {780if (isELFInitializerSection(Sec.getName())) {781InitSections.push_back(&Sec);782}783}784785// Dump the scraped inits.786LLVM_DEBUG({787dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";788for (auto *Sec : InitSections) {789jitlink::SectionRange R(*Sec);790dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n";791}792});793794return MP.registerInitInfo(JD, InitSections);795}796797Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(798jitlink::LinkGraph &G, JITDylib &JD) {799800for (auto *Sym : G.external_symbols()) {801if (Sym->getName() == "__tls_get_addr") {802Sym->setName("___orc_rt_elfnix_tls_get_addr");803} else if (Sym->getName() == "__tlsdesc_resolver") {804Sym->setName("___orc_rt_elfnix_tlsdesc_resolver");805}806}807808auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");809810if (TLSInfoEntrySection) {811std::optional<uint64_t> Key;812{813std::lock_guard<std::mutex> Lock(MP.PlatformMutex);814auto I = MP.JITDylibToPThreadKey.find(&JD);815if (I != MP.JITDylibToPThreadKey.end())816Key = I->second;817}818if (!Key) {819if (auto KeyOrErr = MP.createPThreadKey())820Key = *KeyOrErr;821else822return KeyOrErr.takeError();823}824825uint64_t PlatformKeyBits =826support::endian::byte_swap(*Key, G.getEndianness());827828for (auto *B : TLSInfoEntrySection->blocks()) {829// FIXME: The TLS descriptor byte length may different with different830// ISA831assert(B->getSize() == (G.getPointerSize() * 2) &&832"TLS descriptor must be 2 words length");833auto TLSInfoEntryContent = B->getMutableContent(G);834memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());835}836}837838return Error::success();839}840841} // End namespace orc.842} // End namespace llvm.843844845