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 void LazyCallThroughManager::NotifyResolvedFunction::anchor() {} 20 21 LazyCallThroughManager::LazyCallThroughManager( 22 ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, 23 std::unique_ptr<TrampolinePool> TP) 24 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {} 25 26 Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline( 27 JITDylib &SourceJD, SymbolStringPtr SymbolName, 28 std::shared_ptr<NotifyResolvedFunction> NotifyResolved) { 29 std::lock_guard<std::mutex> Lock(LCTMMutex); 30 auto Trampoline = TP->getTrampoline(); 31 32 if (!Trampoline) 33 return Trampoline.takeError(); 34 35 Reexports[*Trampoline] = std::make_pair(&SourceJD, std::move(SymbolName)); 36 Notifiers[*Trampoline] = std::move(NotifyResolved); 37 return *Trampoline; 38 } 39 40 JITTargetAddress 41 LazyCallThroughManager::callThroughToSymbol(JITTargetAddress TrampolineAddr) { 42 JITDylib *SourceJD = nullptr; 43 SymbolStringPtr SymbolName; 44 45 { 46 std::lock_guard<std::mutex> Lock(LCTMMutex); 47 auto I = Reexports.find(TrampolineAddr); 48 if (I == Reexports.end()) 49 return ErrorHandlerAddr; 50 SourceJD = I->second.first; 51 SymbolName = I->second.second; 52 } 53 54 auto LookupResult = ES.lookup( 55 makeJITDylibSearchOrder(SourceJD, JITDylibLookupFlags::MatchAllSymbols), 56 SymbolName); 57 58 if (!LookupResult) { 59 ES.reportError(LookupResult.takeError()); 60 return ErrorHandlerAddr; 61 } 62 63 auto ResolvedAddr = LookupResult->getAddress(); 64 65 std::shared_ptr<NotifyResolvedFunction> NotifyResolved = nullptr; 66 { 67 std::lock_guard<std::mutex> Lock(LCTMMutex); 68 auto I = Notifiers.find(TrampolineAddr); 69 if (I != Notifiers.end()) { 70 NotifyResolved = I->second; 71 Notifiers.erase(I); 72 } 73 } 74 75 if (NotifyResolved) { 76 if (auto Err = (*NotifyResolved)(*SourceJD, SymbolName, ResolvedAddr)) { 77 ES.reportError(std::move(Err)); 78 return ErrorHandlerAddr; 79 } 80 } 81 82 return ResolvedAddr; 83 } 84 85 Expected<std::unique_ptr<LazyCallThroughManager>> 86 createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, 87 JITTargetAddress ErrorHandlerAddr) { 88 switch (T.getArch()) { 89 default: 90 return make_error<StringError>( 91 std::string("No callback manager available for ") + T.str(), 92 inconvertibleErrorCode()); 93 94 case Triple::aarch64: 95 case Triple::aarch64_32: 96 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES, 97 ErrorHandlerAddr); 98 99 case Triple::x86: 100 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr); 101 102 case Triple::mips: 103 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES, 104 ErrorHandlerAddr); 105 106 case Triple::mipsel: 107 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES, 108 ErrorHandlerAddr); 109 110 case Triple::mips64: 111 case Triple::mips64el: 112 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr); 113 114 case Triple::x86_64: 115 if (T.getOS() == Triple::OSType::Win32) 116 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>( 117 ES, ErrorHandlerAddr); 118 else 119 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>( 120 ES, ErrorHandlerAddr); 121 } 122 } 123 124 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( 125 LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, 126 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc, 127 VModuleKey K) 128 : MaterializationUnit(extractFlags(CallableAliases), std::move(K)), 129 LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), 130 CallableAliases(std::move(CallableAliases)), 131 NotifyResolved(LazyCallThroughManager::createNotifyResolvedFunction( 132 [&ISManager](JITDylib &JD, const SymbolStringPtr &SymbolName, 133 JITTargetAddress ResolvedAddr) { 134 return ISManager.updatePointer(*SymbolName, ResolvedAddr); 135 })), 136 AliaseeTable(SrcJDLoc) {} 137 138 StringRef LazyReexportsMaterializationUnit::getName() const { 139 return "<Lazy Reexports>"; 140 } 141 142 void LazyReexportsMaterializationUnit::materialize( 143 MaterializationResponsibility R) { 144 auto RequestedSymbols = R.getRequestedSymbols(); 145 146 SymbolAliasMap RequestedAliases; 147 for (auto &RequestedSymbol : RequestedSymbols) { 148 auto I = CallableAliases.find(RequestedSymbol); 149 assert(I != CallableAliases.end() && "Symbol not found in alias map?"); 150 RequestedAliases[I->first] = std::move(I->second); 151 CallableAliases.erase(I); 152 } 153 154 if (!CallableAliases.empty()) 155 R.replace(lazyReexports(LCTManager, ISManager, SourceJD, 156 std::move(CallableAliases), AliaseeTable)); 157 158 IndirectStubsManager::StubInitsMap StubInits; 159 for (auto &Alias : RequestedAliases) { 160 161 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline( 162 SourceJD, Alias.second.Aliasee, NotifyResolved); 163 164 if (!CallThroughTrampoline) { 165 SourceJD.getExecutionSession().reportError( 166 CallThroughTrampoline.takeError()); 167 R.failMaterialization(); 168 return; 169 } 170 171 StubInits[*Alias.first] = 172 std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags); 173 } 174 175 if (AliaseeTable != nullptr && !RequestedAliases.empty()) 176 AliaseeTable->trackImpls(RequestedAliases, &SourceJD); 177 178 if (auto Err = ISManager.createStubs(StubInits)) { 179 SourceJD.getExecutionSession().reportError(std::move(Err)); 180 R.failMaterialization(); 181 return; 182 } 183 184 SymbolMap Stubs; 185 for (auto &Alias : RequestedAliases) 186 Stubs[Alias.first] = ISManager.findStub(*Alias.first, false); 187 188 // No registered dependencies, so these calls cannot fail. 189 cantFail(R.notifyResolved(Stubs)); 190 cantFail(R.notifyEmitted()); 191 } 192 193 void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, 194 const SymbolStringPtr &Name) { 195 assert(CallableAliases.count(Name) && 196 "Symbol not covered by this MaterializationUnit"); 197 CallableAliases.erase(Name); 198 } 199 200 SymbolFlagsMap 201 LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { 202 SymbolFlagsMap SymbolFlags; 203 for (auto &KV : Aliases) { 204 assert(KV.second.AliasFlags.isCallable() && 205 "Lazy re-exports must be callable symbols"); 206 SymbolFlags[KV.first] = KV.second.AliasFlags; 207 } 208 return SymbolFlags; 209 } 210 211 } // End namespace orc. 212 } // End namespace llvm. 213