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