Path: blob/main/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.cpp
39566 views
//===- elfnix_platform.cpp ------------------------------------------------===//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//===----------------------------------------------------------------------===//7//8// This file contains code required to load the rest of the ELF-on-*IX runtime.9//10//===----------------------------------------------------------------------===//1112#include "elfnix_platform.h"13#include "common.h"14#include "compiler.h"15#include "error.h"16#include "wrapper_function_utils.h"1718#include <algorithm>19#include <map>20#include <mutex>21#include <sstream>22#include <string_view>23#include <unordered_map>24#include <vector>2526using namespace __orc_rt;27using namespace __orc_rt::elfnix;2829// Declare function tags for functions in the JIT process.30ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_initializers_tag)31ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_deinitializers_tag)32ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag)3334// eh-frame registration functions, made available via aliases35// installed by the Platform36extern "C" void __register_frame(const void *);37extern "C" void __deregister_frame(const void *);3839extern "C" void40__unw_add_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT;41extern "C" void42__unw_remove_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT;4344namespace {4546Error validatePointerSectionExtent(const char *SectionName,47const ExecutorAddrRange &SE) {48if (SE.size() % sizeof(uintptr_t)) {49std::ostringstream ErrMsg;50ErrMsg << std::hex << "Size of " << SectionName << " 0x"51<< SE.Start.getValue() << " -- 0x" << SE.End.getValue()52<< " is not a pointer multiple";53return make_error<StringError>(ErrMsg.str());54}55return Error::success();56}5758Error runInitArray(const std::vector<ExecutorAddrRange> &InitArraySections,59const ELFNixJITDylibInitializers &MOJDIs) {6061for (const auto &ModInits : InitArraySections) {62if (auto Err = validatePointerSectionExtent(".init_array", ModInits))63return Err;6465using InitFunc = void (*)();66for (auto *Init : ModInits.toSpan<InitFunc>())67(*Init)();68}6970return Error::success();71}7273struct TLSInfoEntry {74unsigned long Key = 0;75unsigned long DataAddress = 0;76};7778struct TLSDescriptor {79void (*Resolver)(void *);80TLSInfoEntry *InfoEntry;81};8283class ELFNixPlatformRuntimeState {84private:85struct AtExitEntry {86void (*Func)(void *);87void *Arg;88};8990using AtExitsVector = std::vector<AtExitEntry>;9192struct PerJITDylibState {93void *Header = nullptr;94size_t RefCount = 0;95bool AllowReinitialization = false;96AtExitsVector AtExits;97};9899public:100static void initialize(void *DSOHandle);101static ELFNixPlatformRuntimeState &get();102static void destroy();103104ELFNixPlatformRuntimeState(void *DSOHandle);105106// Delete copy and move constructors.107ELFNixPlatformRuntimeState(const ELFNixPlatformRuntimeState &) = delete;108ELFNixPlatformRuntimeState &109operator=(const ELFNixPlatformRuntimeState &) = delete;110ELFNixPlatformRuntimeState(ELFNixPlatformRuntimeState &&) = delete;111ELFNixPlatformRuntimeState &operator=(ELFNixPlatformRuntimeState &&) = delete;112113Error registerObjectSections(ELFNixPerObjectSectionsToRegister POSR);114Error deregisterObjectSections(ELFNixPerObjectSectionsToRegister POSR);115116const char *dlerror();117void *dlopen(std::string_view Name, int Mode);118int dlclose(void *DSOHandle);119void *dlsym(void *DSOHandle, std::string_view Symbol);120121int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);122void runAtExits(void *DSOHandle);123124/// Returns the base address of the section containing ThreadData.125Expected<std::pair<const char *, size_t>>126getThreadDataSectionFor(const char *ThreadData);127128void *getPlatformJDDSOHandle() { return PlatformJDDSOHandle; }129130private:131PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle);132PerJITDylibState *getJITDylibStateByName(std::string_view Path);133PerJITDylibState &134getOrCreateJITDylibState(ELFNixJITDylibInitializers &MOJDIs);135136Error registerThreadDataSection(span<const char> ThreadDataSection);137138Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,139std::string_view Symbol);140141Expected<ELFNixJITDylibInitializerSequence>142getJITDylibInitializersByName(std::string_view Path);143Expected<void *> dlopenInitialize(std::string_view Path, int Mode);144Error initializeJITDylib(ELFNixJITDylibInitializers &MOJDIs);145146static ELFNixPlatformRuntimeState *MOPS;147148void *PlatformJDDSOHandle;149150// Frame registration functions:151void (*registerEHFrameSection)(const void *) = nullptr;152void (*deregisterEHFrameSection)(const void *) = nullptr;153154// FIXME: Move to thread-state.155std::string DLFcnError;156157std::recursive_mutex JDStatesMutex;158std::unordered_map<void *, PerJITDylibState> JDStates;159std::unordered_map<std::string, void *> JDNameToHeader;160161std::mutex ThreadDataSectionsMutex;162std::map<const char *, size_t> ThreadDataSections;163};164165ELFNixPlatformRuntimeState *ELFNixPlatformRuntimeState::MOPS = nullptr;166167void ELFNixPlatformRuntimeState::initialize(void *DSOHandle) {168assert(!MOPS && "ELFNixPlatformRuntimeState should be null");169MOPS = new ELFNixPlatformRuntimeState(DSOHandle);170}171172ELFNixPlatformRuntimeState &ELFNixPlatformRuntimeState::get() {173assert(MOPS && "ELFNixPlatformRuntimeState not initialized");174return *MOPS;175}176177void ELFNixPlatformRuntimeState::destroy() {178assert(MOPS && "ELFNixPlatformRuntimeState not initialized");179delete MOPS;180}181182ELFNixPlatformRuntimeState::ELFNixPlatformRuntimeState(void *DSOHandle)183: PlatformJDDSOHandle(DSOHandle) {184if (__unw_add_dynamic_eh_frame_section &&185__unw_remove_dynamic_eh_frame_section) {186registerEHFrameSection = __unw_add_dynamic_eh_frame_section;187deregisterEHFrameSection = __unw_remove_dynamic_eh_frame_section;188} else {189registerEHFrameSection = __register_frame;190deregisterEHFrameSection = __deregister_frame;191}192}193194Error ELFNixPlatformRuntimeState::registerObjectSections(195ELFNixPerObjectSectionsToRegister POSR) {196if (POSR.EHFrameSection.Start)197registerEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>());198199if (POSR.ThreadDataSection.Start) {200if (auto Err = registerThreadDataSection(201POSR.ThreadDataSection.toSpan<const char>()))202return Err;203}204205return Error::success();206}207208Error ELFNixPlatformRuntimeState::deregisterObjectSections(209ELFNixPerObjectSectionsToRegister POSR) {210if (POSR.EHFrameSection.Start)211deregisterEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>());212213return Error::success();214}215216const char *ELFNixPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }217218void *ELFNixPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {219std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);220221// Use fast path if all JITDylibs are already loaded and don't require222// re-running initializers.223if (auto *JDS = getJITDylibStateByName(Path)) {224if (!JDS->AllowReinitialization) {225++JDS->RefCount;226return JDS->Header;227}228}229230auto H = dlopenInitialize(Path, Mode);231if (!H) {232DLFcnError = toString(H.takeError());233return nullptr;234}235236return *H;237}238239int ELFNixPlatformRuntimeState::dlclose(void *DSOHandle) {240runAtExits(DSOHandle);241return 0;242}243244void *ELFNixPlatformRuntimeState::dlsym(void *DSOHandle,245std::string_view Symbol) {246auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol);247if (!Addr) {248DLFcnError = toString(Addr.takeError());249return 0;250}251252return Addr->toPtr<void *>();253}254255int ELFNixPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,256void *DSOHandle) {257// FIXME: Handle out-of-memory errors, returning -1 if OOM.258std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);259auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);260assert(JDS && "JITDylib state not initialized");261JDS->AtExits.push_back({F, Arg});262return 0;263}264265void ELFNixPlatformRuntimeState::runAtExits(void *DSOHandle) {266// FIXME: Should atexits be allowed to run concurrently with access to267// JDState?268AtExitsVector V;269{270std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);271auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);272assert(JDS && "JITDlybi state not initialized");273std::swap(V, JDS->AtExits);274}275276while (!V.empty()) {277auto &AE = V.back();278AE.Func(AE.Arg);279V.pop_back();280}281}282283Expected<std::pair<const char *, size_t>>284ELFNixPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {285std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);286auto I = ThreadDataSections.upper_bound(ThreadData);287// Check that we have a valid entry conovering this address.288if (I == ThreadDataSections.begin())289return make_error<StringError>("No thread local data section for key");290I = std::prev(I);291if (ThreadData >= I->first + I->second)292return make_error<StringError>("No thread local data section for key");293return *I;294}295296ELFNixPlatformRuntimeState::PerJITDylibState *297ELFNixPlatformRuntimeState::getJITDylibStateByHeaderAddr(void *DSOHandle) {298auto I = JDStates.find(DSOHandle);299if (I == JDStates.end())300return nullptr;301return &I->second;302}303304ELFNixPlatformRuntimeState::PerJITDylibState *305ELFNixPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {306// FIXME: Avoid creating string copy here.307auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));308if (I == JDNameToHeader.end())309return nullptr;310void *H = I->second;311auto J = JDStates.find(H);312assert(J != JDStates.end() &&313"JITDylib has name map entry but no header map entry");314return &J->second;315}316317ELFNixPlatformRuntimeState::PerJITDylibState &318ELFNixPlatformRuntimeState::getOrCreateJITDylibState(319ELFNixJITDylibInitializers &MOJDIs) {320void *Header = MOJDIs.DSOHandleAddress.toPtr<void *>();321322auto &JDS = JDStates[Header];323324// If this entry hasn't been created yet.325if (!JDS.Header) {326assert(!JDNameToHeader.count(MOJDIs.Name) &&327"JITDylib has header map entry but no name map entry");328JDNameToHeader[MOJDIs.Name] = Header;329JDS.Header = Header;330}331332return JDS;333}334335Error ELFNixPlatformRuntimeState::registerThreadDataSection(336span<const char> ThreadDataSection) {337std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);338auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());339if (I != ThreadDataSections.begin()) {340auto J = std::prev(I);341if (J->first + J->second > ThreadDataSection.data())342return make_error<StringError>("Overlapping .tdata sections");343}344ThreadDataSections.insert(345I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));346return Error::success();347}348349Expected<ExecutorAddr>350ELFNixPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,351std::string_view Sym) {352Expected<ExecutorAddr> Result((ExecutorAddr()));353if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(354SPSExecutorAddr, SPSString)>::call(&__orc_rt_elfnix_symbol_lookup_tag,355Result,356ExecutorAddr::fromPtr(DSOHandle),357Sym))358return std::move(Err);359return Result;360}361362Expected<ELFNixJITDylibInitializerSequence>363ELFNixPlatformRuntimeState::getJITDylibInitializersByName(364std::string_view Path) {365Expected<ELFNixJITDylibInitializerSequence> Result(366(ELFNixJITDylibInitializerSequence()));367std::string PathStr(Path.data(), Path.size());368if (auto Err =369WrapperFunction<SPSExpected<SPSELFNixJITDylibInitializerSequence>(370SPSString)>::call(&__orc_rt_elfnix_get_initializers_tag, Result,371Path))372return std::move(Err);373return Result;374}375376Expected<void *>377ELFNixPlatformRuntimeState::dlopenInitialize(std::string_view Path, int Mode) {378// Either our JITDylib wasn't loaded, or it or one of its dependencies allows379// reinitialization. We need to call in to the JIT to see if there's any new380// work pending.381auto InitSeq = getJITDylibInitializersByName(Path);382if (!InitSeq)383return InitSeq.takeError();384385// Init sequences should be non-empty.386if (InitSeq->empty())387return make_error<StringError>(388"__orc_rt_elfnix_get_initializers returned an "389"empty init sequence");390391// Otherwise register and run initializers for each JITDylib.392for (auto &MOJDIs : *InitSeq)393if (auto Err = initializeJITDylib(MOJDIs))394return std::move(Err);395396// Return the header for the last item in the list.397auto *JDS = getJITDylibStateByHeaderAddr(398InitSeq->back().DSOHandleAddress.toPtr<void *>());399assert(JDS && "Missing state entry for JD");400return JDS->Header;401}402403long getPriority(const std::string &name) {404auto pos = name.find_last_not_of("0123456789");405if (pos == name.size() - 1)406return 65535;407else408return std::strtol(name.c_str() + pos + 1, nullptr, 10);409}410411Error ELFNixPlatformRuntimeState::initializeJITDylib(412ELFNixJITDylibInitializers &MOJDIs) {413414auto &JDS = getOrCreateJITDylibState(MOJDIs);415++JDS.RefCount;416417using SectionList = std::vector<ExecutorAddrRange>;418std::sort(MOJDIs.InitSections.begin(), MOJDIs.InitSections.end(),419[](const std::pair<std::string, SectionList> &LHS,420const std::pair<std::string, SectionList> &RHS) -> bool {421return getPriority(LHS.first) < getPriority(RHS.first);422});423for (auto &Entry : MOJDIs.InitSections)424if (auto Err = runInitArray(Entry.second, MOJDIs))425return Err;426427return Error::success();428}429class ELFNixPlatformRuntimeTLVManager {430public:431void *getInstance(const char *ThreadData);432433private:434std::unordered_map<const char *, char *> Instances;435std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;436};437438void *ELFNixPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {439auto I = Instances.find(ThreadData);440if (I != Instances.end())441return I->second;442auto TDS =443ELFNixPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);444if (!TDS) {445__orc_rt_log_error(toString(TDS.takeError()).c_str());446return nullptr;447}448449auto &Allocated = AllocatedSections[TDS->first];450if (!Allocated) {451Allocated = std::make_unique<char[]>(TDS->second);452memcpy(Allocated.get(), TDS->first, TDS->second);453}454size_t ThreadDataDelta = ThreadData - TDS->first;455assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");456457char *Instance = Allocated.get() + ThreadDataDelta;458Instances[ThreadData] = Instance;459return Instance;460}461462void destroyELFNixTLVMgr(void *ELFNixTLVMgr) {463delete static_cast<ELFNixPlatformRuntimeTLVManager *>(ELFNixTLVMgr);464}465466} // end anonymous namespace467468//------------------------------------------------------------------------------469// JIT entry points470//------------------------------------------------------------------------------471472ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult473__orc_rt_elfnix_platform_bootstrap(char *ArgData, size_t ArgSize) {474return WrapperFunction<void(uint64_t)>::handle(475ArgData, ArgSize,476[](uint64_t &DSOHandle) {477ELFNixPlatformRuntimeState::initialize(478reinterpret_cast<void *>(DSOHandle));479})480.release();481}482483ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult484__orc_rt_elfnix_platform_shutdown(char *ArgData, size_t ArgSize) {485ELFNixPlatformRuntimeState::destroy();486return WrapperFunctionResult().release();487}488489/// Wrapper function for registering metadata on a per-object basis.490ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult491__orc_rt_elfnix_register_object_sections(char *ArgData, size_t ArgSize) {492return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>::493handle(ArgData, ArgSize,494[](ELFNixPerObjectSectionsToRegister &POSR) {495return ELFNixPlatformRuntimeState::get().registerObjectSections(496std::move(POSR));497})498.release();499}500501/// Wrapper for releasing per-object metadat.502ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult503__orc_rt_elfnix_deregister_object_sections(char *ArgData, size_t ArgSize) {504return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>::505handle(ArgData, ArgSize,506[](ELFNixPerObjectSectionsToRegister &POSR) {507return ELFNixPlatformRuntimeState::get()508.deregisterObjectSections(std::move(POSR));509})510.release();511}512513//------------------------------------------------------------------------------514// TLV support515//------------------------------------------------------------------------------516517ORC_RT_INTERFACE void *__orc_rt_elfnix_tls_get_addr_impl(TLSInfoEntry *D) {518auto *TLVMgr = static_cast<ELFNixPlatformRuntimeTLVManager *>(519pthread_getspecific(D->Key));520if (!TLVMgr)521TLVMgr = new ELFNixPlatformRuntimeTLVManager();522if (pthread_setspecific(D->Key, TLVMgr)) {523__orc_rt_log_error("Call to pthread_setspecific failed");524return nullptr;525}526527return TLVMgr->getInstance(528reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));529}530531ORC_RT_INTERFACE ptrdiff_t ___orc_rt_elfnix_tlsdesc_resolver_impl(532TLSDescriptor *D, const char *ThreadPointer) {533const char *TLVPtr = reinterpret_cast<const char *>(534__orc_rt_elfnix_tls_get_addr_impl(D->InfoEntry));535return TLVPtr - ThreadPointer;536}537538ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult539__orc_rt_elfnix_create_pthread_key(char *ArgData, size_t ArgSize) {540return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(541ArgData, ArgSize,542[]() -> Expected<uint64_t> {543pthread_key_t Key;544if (int Err = pthread_key_create(&Key, destroyELFNixTLVMgr)) {545__orc_rt_log_error("Call to pthread_key_create failed");546return make_error<StringError>(strerror(Err));547}548return static_cast<uint64_t>(Key);549})550.release();551}552553//------------------------------------------------------------------------------554// cxa_atexit support555//------------------------------------------------------------------------------556557int __orc_rt_elfnix_cxa_atexit(void (*func)(void *), void *arg,558void *dso_handle) {559return ELFNixPlatformRuntimeState::get().registerAtExit(func, arg,560dso_handle);561}562563int __orc_rt_elfnix_atexit(void (*func)(void *)) {564auto &PlatformRTState = ELFNixPlatformRuntimeState::get();565return ELFNixPlatformRuntimeState::get().registerAtExit(566func, NULL, PlatformRTState.getPlatformJDDSOHandle());567}568569void __orc_rt_elfnix_cxa_finalize(void *dso_handle) {570ELFNixPlatformRuntimeState::get().runAtExits(dso_handle);571}572573//------------------------------------------------------------------------------574// JIT'd dlfcn alternatives.575//------------------------------------------------------------------------------576577const char *__orc_rt_elfnix_jit_dlerror() {578return ELFNixPlatformRuntimeState::get().dlerror();579}580581void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode) {582return ELFNixPlatformRuntimeState::get().dlopen(path, mode);583}584585int __orc_rt_elfnix_jit_dlclose(void *dso_handle) {586return ELFNixPlatformRuntimeState::get().dlclose(dso_handle);587}588589void *__orc_rt_elfnix_jit_dlsym(void *dso_handle, const char *symbol) {590return ELFNixPlatformRuntimeState::get().dlsym(dso_handle, symbol);591}592593//------------------------------------------------------------------------------594// ELFNix Run Program595//------------------------------------------------------------------------------596597ORC_RT_INTERFACE int64_t __orc_rt_elfnix_run_program(598const char *JITDylibName, const char *EntrySymbolName, int argc,599char *argv[]) {600using MainTy = int (*)(int, char *[]);601602void *H = __orc_rt_elfnix_jit_dlopen(JITDylibName,603__orc_rt::elfnix::ORC_RT_RTLD_LAZY);604if (!H) {605__orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());606return -1;607}608609auto *Main =610reinterpret_cast<MainTy>(__orc_rt_elfnix_jit_dlsym(H, EntrySymbolName));611612if (!Main) {613__orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());614return -1;615}616617int Result = Main(argc, argv);618619if (__orc_rt_elfnix_jit_dlclose(H) == -1)620__orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());621622return Result;623}624625626