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