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