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