Home | History | Annotate | Line # | Download | only in Orc
      1 //===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
      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/LazyReexports.h"
     10 
     11 #include "llvm/ADT/Triple.h"
     12 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
     13 
     14 #define DEBUG_TYPE "orc"
     15 
     16 namespace llvm {
     17 namespace orc {
     18 
     19 LazyCallThroughManager::LazyCallThroughManager(
     20     ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
     21     : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
     22 
     23 Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
     24     JITDylib &SourceJD, SymbolStringPtr SymbolName,
     25     NotifyResolvedFunction NotifyResolved) {
     26   assert(TP && "TrampolinePool not set");
     27 
     28   std::lock_guard<std::mutex> Lock(LCTMMutex);
     29   auto Trampoline = TP->getTrampoline();
     30 
     31   if (!Trampoline)
     32     return Trampoline.takeError();
     33 
     34   Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
     35   Notifiers[*Trampoline] = std::move(NotifyResolved);
     36   return *Trampoline;
     37 }
     38 
     39 JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
     40   ES.reportError(std::move(Err));
     41   return ErrorHandlerAddr;
     42 }
     43 
     44 Expected<LazyCallThroughManager::ReexportsEntry>
     45 LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
     46   std::lock_guard<std::mutex> Lock(LCTMMutex);
     47   auto I = Reexports.find(TrampolineAddr);
     48   if (I == Reexports.end())
     49     return createStringError(inconvertibleErrorCode(),
     50                              "Missing reexport for trampoline address %p",
     51                              TrampolineAddr);
     52   return I->second;
     53 }
     54 
     55 Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
     56                                              JITTargetAddress ResolvedAddr) {
     57   NotifyResolvedFunction NotifyResolved;
     58   {
     59     std::lock_guard<std::mutex> Lock(LCTMMutex);
     60     auto I = Notifiers.find(TrampolineAddr);
     61     if (I != Notifiers.end()) {
     62       NotifyResolved = std::move(I->second);
     63       Notifiers.erase(I);
     64     }
     65   }
     66 
     67   return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
     68 }
     69 
     70 void LazyCallThroughManager::resolveTrampolineLandingAddress(
     71     JITTargetAddress TrampolineAddr,
     72     NotifyLandingResolvedFunction NotifyLandingResolved) {
     73 
     74   auto Entry = findReexport(TrampolineAddr);
     75   if (!Entry)
     76     return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
     77 
     78   // Declaring SLS and the callback outside of the call to ES.lookup is a
     79   // workaround to fix build failures on AIX and on z/OS platforms.
     80   SymbolLookupSet SLS({Entry->SymbolName});
     81   auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
     82                    NotifyLandingResolved = std::move(NotifyLandingResolved)](
     83                       Expected<SymbolMap> Result) mutable {
     84     if (Result) {
     85       assert(Result->size() == 1 && "Unexpected result size");
     86       assert(Result->count(SymbolName) && "Unexpected result value");
     87       JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
     88 
     89       if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
     90         NotifyLandingResolved(reportCallThroughError(std::move(Err)));
     91       else
     92         NotifyLandingResolved(LandingAddr);
     93     } else {
     94       NotifyLandingResolved(reportCallThroughError(Result.takeError()));
     95     }
     96   };
     97 
     98   ES.lookup(LookupKind::Static,
     99             makeJITDylibSearchOrder(Entry->SourceJD,
    100                                     JITDylibLookupFlags::MatchAllSymbols),
    101             std::move(SLS), SymbolState::Ready, std::move(Callback),
    102             NoDependenciesToRegister);
    103 }
    104 
    105 Expected<std::unique_ptr<LazyCallThroughManager>>
    106 createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
    107                                   JITTargetAddress ErrorHandlerAddr) {
    108   switch (T.getArch()) {
    109   default:
    110     return make_error<StringError>(
    111         std::string("No callback manager available for ") + T.str(),
    112         inconvertibleErrorCode());
    113 
    114   case Triple::aarch64:
    115   case Triple::aarch64_32:
    116     return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
    117                                                            ErrorHandlerAddr);
    118 
    119   case Triple::x86:
    120     return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
    121 
    122   case Triple::mips:
    123     return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
    124                                                             ErrorHandlerAddr);
    125 
    126   case Triple::mipsel:
    127     return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
    128                                                             ErrorHandlerAddr);
    129 
    130   case Triple::mips64:
    131   case Triple::mips64el:
    132     return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
    133 
    134   case Triple::x86_64:
    135     if (T.getOS() == Triple::OSType::Win32)
    136       return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
    137           ES, ErrorHandlerAddr);
    138     else
    139       return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
    140           ES, ErrorHandlerAddr);
    141   }
    142 }
    143 
    144 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
    145     LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
    146     JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
    147     : MaterializationUnit(extractFlags(CallableAliases), nullptr),
    148       LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
    149       CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
    150 
    151 StringRef LazyReexportsMaterializationUnit::getName() const {
    152   return "<Lazy Reexports>";
    153 }
    154 
    155 void LazyReexportsMaterializationUnit::materialize(
    156     std::unique_ptr<MaterializationResponsibility> R) {
    157   auto RequestedSymbols = R->getRequestedSymbols();
    158 
    159   SymbolAliasMap RequestedAliases;
    160   for (auto &RequestedSymbol : RequestedSymbols) {
    161     auto I = CallableAliases.find(RequestedSymbol);
    162     assert(I != CallableAliases.end() && "Symbol not found in alias map?");
    163     RequestedAliases[I->first] = std::move(I->second);
    164     CallableAliases.erase(I);
    165   }
    166 
    167   if (!CallableAliases.empty())
    168     if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
    169                                             std::move(CallableAliases),
    170                                             AliaseeTable))) {
    171       R->getExecutionSession().reportError(std::move(Err));
    172       R->failMaterialization();
    173       return;
    174     }
    175 
    176   IndirectStubsManager::StubInitsMap StubInits;
    177   for (auto &Alias : RequestedAliases) {
    178 
    179     auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
    180         SourceJD, Alias.second.Aliasee,
    181         [&ISManager = this->ISManager,
    182          StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
    183           return ISManager.updatePointer(*StubSym, ResolvedAddr);
    184         });
    185 
    186     if (!CallThroughTrampoline) {
    187       SourceJD.getExecutionSession().reportError(
    188           CallThroughTrampoline.takeError());
    189       R->failMaterialization();
    190       return;
    191     }
    192 
    193     StubInits[*Alias.first] =
    194         std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
    195   }
    196 
    197   if (AliaseeTable != nullptr && !RequestedAliases.empty())
    198     AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
    199 
    200   if (auto Err = ISManager.createStubs(StubInits)) {
    201     SourceJD.getExecutionSession().reportError(std::move(Err));
    202     R->failMaterialization();
    203     return;
    204   }
    205 
    206   SymbolMap Stubs;
    207   for (auto &Alias : RequestedAliases)
    208     Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
    209 
    210   // No registered dependencies, so these calls cannot fail.
    211   cantFail(R->notifyResolved(Stubs));
    212   cantFail(R->notifyEmitted());
    213 }
    214 
    215 void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
    216                                                const SymbolStringPtr &Name) {
    217   assert(CallableAliases.count(Name) &&
    218          "Symbol not covered by this MaterializationUnit");
    219   CallableAliases.erase(Name);
    220 }
    221 
    222 SymbolFlagsMap
    223 LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
    224   SymbolFlagsMap SymbolFlags;
    225   for (auto &KV : Aliases) {
    226     assert(KV.second.AliasFlags.isCallable() &&
    227            "Lazy re-exports must be callable symbols");
    228     SymbolFlags[KV.first] = KV.second.AliasFlags;
    229   }
    230   return SymbolFlags;
    231 }
    232 
    233 } // End namespace orc.
    234 } // End namespace llvm.
    235