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