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