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::loongarch64: 123 return LocalLazyCallThroughManager::Create<OrcLoongArch64>( 124 ES, ErrorHandlerAddr); 125 126 case Triple::mips: 127 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES, 128 ErrorHandlerAddr); 129 130 case Triple::mipsel: 131 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES, 132 ErrorHandlerAddr); 133 134 case Triple::mips64: 135 case Triple::mips64el: 136 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr); 137 138 case Triple::riscv64: 139 return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES, 140 ErrorHandlerAddr); 141 142 case Triple::x86_64: 143 if (T.getOS() == Triple::OSType::Win32) 144 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>( 145 ES, ErrorHandlerAddr); 146 else 147 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>( 148 ES, ErrorHandlerAddr); 149 } 150 } 151 152 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( 153 LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, 154 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc) 155 : MaterializationUnit(extractFlags(CallableAliases)), 156 LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), 157 CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {} 158 159 StringRef LazyReexportsMaterializationUnit::getName() const { 160 return "<Lazy Reexports>"; 161 } 162 163 void LazyReexportsMaterializationUnit::materialize( 164 std::unique_ptr<MaterializationResponsibility> R) { 165 auto RequestedSymbols = R->getRequestedSymbols(); 166 167 SymbolAliasMap RequestedAliases; 168 for (auto &RequestedSymbol : RequestedSymbols) { 169 auto I = CallableAliases.find(RequestedSymbol); 170 assert(I != CallableAliases.end() && "Symbol not found in alias map?"); 171 RequestedAliases[I->first] = std::move(I->second); 172 CallableAliases.erase(I); 173 } 174 175 if (!CallableAliases.empty()) 176 if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD, 177 std::move(CallableAliases), 178 AliaseeTable))) { 179 R->getExecutionSession().reportError(std::move(Err)); 180 R->failMaterialization(); 181 return; 182 } 183 184 IndirectStubsManager::StubInitsMap StubInits; 185 for (auto &Alias : RequestedAliases) { 186 187 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline( 188 SourceJD, Alias.second.Aliasee, 189 [&ISManager = this->ISManager, 190 StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error { 191 return ISManager.updatePointer(*StubSym, ResolvedAddr); 192 }); 193 194 if (!CallThroughTrampoline) { 195 SourceJD.getExecutionSession().reportError( 196 CallThroughTrampoline.takeError()); 197 R->failMaterialization(); 198 return; 199 } 200 201 StubInits[*Alias.first] = 202 std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags); 203 } 204 205 if (AliaseeTable != nullptr && !RequestedAliases.empty()) 206 AliaseeTable->trackImpls(RequestedAliases, &SourceJD); 207 208 if (auto Err = ISManager.createStubs(StubInits)) { 209 SourceJD.getExecutionSession().reportError(std::move(Err)); 210 R->failMaterialization(); 211 return; 212 } 213 214 SymbolMap Stubs; 215 for (auto &Alias : RequestedAliases) 216 Stubs[Alias.first] = ISManager.findStub(*Alias.first, false); 217 218 // No registered dependencies, so these calls cannot fail. 219 cantFail(R->notifyResolved(Stubs)); 220 cantFail(R->notifyEmitted()); 221 } 222 223 void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, 224 const SymbolStringPtr &Name) { 225 assert(CallableAliases.count(Name) && 226 "Symbol not covered by this MaterializationUnit"); 227 CallableAliases.erase(Name); 228 } 229 230 MaterializationUnit::Interface 231 LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { 232 SymbolFlagsMap SymbolFlags; 233 for (auto &KV : Aliases) { 234 assert(KV.second.AliasFlags.isCallable() && 235 "Lazy re-exports must be callable symbols"); 236 SymbolFlags[KV.first] = KV.second.AliasFlags; 237 } 238 return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr); 239 } 240 241 } // End namespace orc. 242 } // End namespace llvm. 243