1 | //===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===// |
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/ExecutionUtils.h" |
10 | #include "llvm/ExecutionEngine/JITLink/x86_64.h" |
11 | #include "llvm/ExecutionEngine/Orc/Layer.h" |
12 | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" |
13 | #include "llvm/IR/Constants.h" |
14 | #include "llvm/IR/Function.h" |
15 | #include "llvm/IR/GlobalVariable.h" |
16 | #include "llvm/IR/Module.h" |
17 | #include "llvm/MC/TargetRegistry.h" |
18 | #include "llvm/Object/MachOUniversal.h" |
19 | #include "llvm/Support/FormatVariadic.h" |
20 | #include "llvm/Target/TargetMachine.h" |
21 | #include <string> |
22 | |
23 | namespace llvm { |
24 | namespace orc { |
25 | |
26 | CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End) |
27 | : InitList( |
28 | GV ? dyn_cast_or_null<ConstantArray>(Val: GV->getInitializer()) : nullptr), |
29 | I((InitList && End) ? InitList->getNumOperands() : 0) { |
30 | } |
31 | |
32 | bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const { |
33 | assert(InitList == Other.InitList && "Incomparable iterators." ); |
34 | return I == Other.I; |
35 | } |
36 | |
37 | bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const { |
38 | return !(*this == Other); |
39 | } |
40 | |
41 | CtorDtorIterator& CtorDtorIterator::operator++() { |
42 | ++I; |
43 | return *this; |
44 | } |
45 | |
46 | CtorDtorIterator CtorDtorIterator::operator++(int) { |
47 | CtorDtorIterator Temp = *this; |
48 | ++I; |
49 | return Temp; |
50 | } |
51 | |
52 | CtorDtorIterator::Element CtorDtorIterator::operator*() const { |
53 | ConstantStruct *CS = dyn_cast<ConstantStruct>(Val: InitList->getOperand(i_nocapture: I)); |
54 | assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors" ); |
55 | |
56 | Constant *FuncC = CS->getOperand(i_nocapture: 1); |
57 | Function *Func = nullptr; |
58 | |
59 | // Extract function pointer, pulling off any casts. |
60 | while (FuncC) { |
61 | if (Function *F = dyn_cast_or_null<Function>(Val: FuncC)) { |
62 | Func = F; |
63 | break; |
64 | } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(Val: FuncC)) { |
65 | if (CE->isCast()) |
66 | FuncC = CE->getOperand(i_nocapture: 0); |
67 | else |
68 | break; |
69 | } else { |
70 | // This isn't anything we recognize. Bail out with Func left set to null. |
71 | break; |
72 | } |
73 | } |
74 | |
75 | auto *Priority = cast<ConstantInt>(Val: CS->getOperand(i_nocapture: 0)); |
76 | Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(i_nocapture: 2) : nullptr; |
77 | if (Data && !isa<GlobalValue>(Val: Data)) |
78 | Data = nullptr; |
79 | return Element(Priority->getZExtValue(), Func, Data); |
80 | } |
81 | |
82 | iterator_range<CtorDtorIterator> getConstructors(const Module &M) { |
83 | const GlobalVariable *CtorsList = M.getNamedGlobal(Name: "llvm.global_ctors" ); |
84 | return make_range(x: CtorDtorIterator(CtorsList, false), |
85 | y: CtorDtorIterator(CtorsList, true)); |
86 | } |
87 | |
88 | iterator_range<CtorDtorIterator> getDestructors(const Module &M) { |
89 | const GlobalVariable *DtorsList = M.getNamedGlobal(Name: "llvm.global_dtors" ); |
90 | return make_range(x: CtorDtorIterator(DtorsList, false), |
91 | y: CtorDtorIterator(DtorsList, true)); |
92 | } |
93 | |
94 | bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue &GV) { |
95 | if (GV.isDeclaration()) |
96 | return false; |
97 | |
98 | if (GV.hasName() && (GV.getName() == "llvm.global_ctors" || |
99 | GV.getName() == "llvm.global_dtors" )) |
100 | return true; |
101 | |
102 | if (ObjFmt == Triple::MachO) { |
103 | // FIXME: These section checks are too strict: We should match first and |
104 | // second word split by comma. |
105 | if (GV.hasSection() && |
106 | (GV.getSection().starts_with(Prefix: "__DATA,__objc_classlist" ) || |
107 | GV.getSection().starts_with(Prefix: "__DATA,__objc_selrefs" ))) |
108 | return true; |
109 | } |
110 | |
111 | return false; |
112 | } |
113 | |
114 | void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) { |
115 | if (CtorDtors.empty()) |
116 | return; |
117 | |
118 | MangleAndInterner Mangle( |
119 | JD.getExecutionSession(), |
120 | (*CtorDtors.begin()).Func->getParent()->getDataLayout()); |
121 | |
122 | for (auto CtorDtor : CtorDtors) { |
123 | assert(CtorDtor.Func && CtorDtor.Func->hasName() && |
124 | "Ctor/Dtor function must be named to be runnable under the JIT" ); |
125 | |
126 | // FIXME: Maybe use a symbol promoter here instead. |
127 | if (CtorDtor.Func->hasLocalLinkage()) { |
128 | CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage); |
129 | CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility); |
130 | } |
131 | |
132 | if (CtorDtor.Data && cast<GlobalValue>(Val: CtorDtor.Data)->isDeclaration()) { |
133 | dbgs() << " Skipping because why now?\n" ; |
134 | continue; |
135 | } |
136 | |
137 | CtorDtorsByPriority[CtorDtor.Priority].push_back( |
138 | x: Mangle(CtorDtor.Func->getName())); |
139 | } |
140 | } |
141 | |
142 | Error CtorDtorRunner::run() { |
143 | using CtorDtorTy = void (*)(); |
144 | |
145 | SymbolLookupSet LookupSet; |
146 | for (auto &KV : CtorDtorsByPriority) |
147 | for (auto &Name : KV.second) |
148 | LookupSet.add(Name); |
149 | assert(!LookupSet.containsDuplicates() && |
150 | "Ctor/Dtor list contains duplicates" ); |
151 | |
152 | auto &ES = JD.getExecutionSession(); |
153 | if (auto CtorDtorMap = ES.lookup( |
154 | SearchOrder: makeJITDylibSearchOrder(JDs: &JD, Flags: JITDylibLookupFlags::MatchAllSymbols), |
155 | Symbols: std::move(LookupSet))) { |
156 | for (auto &KV : CtorDtorsByPriority) { |
157 | for (auto &Name : KV.second) { |
158 | assert(CtorDtorMap->count(Name) && "No entry for Name" ); |
159 | auto CtorDtor = (*CtorDtorMap)[Name].getAddress().toPtr<CtorDtorTy>(); |
160 | CtorDtor(); |
161 | } |
162 | } |
163 | CtorDtorsByPriority.clear(); |
164 | return Error::success(); |
165 | } else |
166 | return CtorDtorMap.takeError(); |
167 | } |
168 | |
169 | void LocalCXXRuntimeOverridesBase::runDestructors() { |
170 | auto& CXXDestructorDataPairs = DSOHandleOverride; |
171 | for (auto &P : CXXDestructorDataPairs) |
172 | P.first(P.second); |
173 | CXXDestructorDataPairs.clear(); |
174 | } |
175 | |
176 | int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, |
177 | void *Arg, |
178 | void *DSOHandle) { |
179 | auto& CXXDestructorDataPairs = |
180 | *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); |
181 | CXXDestructorDataPairs.push_back(x: std::make_pair(x&: Destructor, y&: Arg)); |
182 | return 0; |
183 | } |
184 | |
185 | Error LocalCXXRuntimeOverrides::enable(JITDylib &JD, |
186 | MangleAndInterner &Mangle) { |
187 | SymbolMap RuntimeInterposes; |
188 | RuntimeInterposes[Mangle("__dso_handle" )] = { |
189 | ExecutorAddr::fromPtr(Ptr: &DSOHandleOverride), JITSymbolFlags::Exported}; |
190 | RuntimeInterposes[Mangle("__cxa_atexit" )] = { |
191 | ExecutorAddr::fromPtr(Ptr: &CXAAtExitOverride), JITSymbolFlags::Exported}; |
192 | |
193 | return JD.define(MU: absoluteSymbols(Symbols: std::move(RuntimeInterposes))); |
194 | } |
195 | |
196 | void ItaniumCXAAtExitSupport::registerAtExit(void (*F)(void *), void *Ctx, |
197 | void *DSOHandle) { |
198 | std::lock_guard<std::mutex> Lock(AtExitsMutex); |
199 | AtExitRecords[DSOHandle].push_back(x: {.F: F, .Ctx: Ctx}); |
200 | } |
201 | |
202 | void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle) { |
203 | std::vector<AtExitRecord> AtExitsToRun; |
204 | |
205 | { |
206 | std::lock_guard<std::mutex> Lock(AtExitsMutex); |
207 | auto I = AtExitRecords.find(Val: DSOHandle); |
208 | if (I != AtExitRecords.end()) { |
209 | AtExitsToRun = std::move(I->second); |
210 | AtExitRecords.erase(I); |
211 | } |
212 | } |
213 | |
214 | while (!AtExitsToRun.empty()) { |
215 | AtExitsToRun.back().F(AtExitsToRun.back().Ctx); |
216 | AtExitsToRun.pop_back(); |
217 | } |
218 | } |
219 | |
220 | DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator( |
221 | sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow, |
222 | AddAbsoluteSymbolsFn AddAbsoluteSymbols) |
223 | : Dylib(std::move(Dylib)), Allow(std::move(Allow)), |
224 | AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)), |
225 | GlobalPrefix(GlobalPrefix) {} |
226 | |
227 | Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
228 | DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix, |
229 | SymbolPredicate Allow, |
230 | AddAbsoluteSymbolsFn AddAbsoluteSymbols) { |
231 | std::string ErrMsg; |
232 | auto Lib = sys::DynamicLibrary::getPermanentLibrary(filename: FileName, errMsg: &ErrMsg); |
233 | if (!Lib.isValid()) |
234 | return make_error<StringError>(Args: std::move(ErrMsg), Args: inconvertibleErrorCode()); |
235 | return std::make_unique<DynamicLibrarySearchGenerator>( |
236 | args: std::move(Lib), args&: GlobalPrefix, args: std::move(Allow), |
237 | args: std::move(AddAbsoluteSymbols)); |
238 | } |
239 | |
240 | Error DynamicLibrarySearchGenerator::tryToGenerate( |
241 | LookupState &LS, LookupKind K, JITDylib &JD, |
242 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { |
243 | orc::SymbolMap NewSymbols; |
244 | |
245 | bool HasGlobalPrefix = (GlobalPrefix != '\0'); |
246 | |
247 | for (auto &KV : Symbols) { |
248 | auto &Name = KV.first; |
249 | |
250 | if ((*Name).empty()) |
251 | continue; |
252 | |
253 | if (Allow && !Allow(Name)) |
254 | continue; |
255 | |
256 | if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) |
257 | continue; |
258 | |
259 | std::string Tmp((*Name).data() + HasGlobalPrefix, |
260 | (*Name).size() - HasGlobalPrefix); |
261 | if (void *P = Dylib.getAddressOfSymbol(symbolName: Tmp.c_str())) |
262 | NewSymbols[Name] = {ExecutorAddr::fromPtr(Ptr: P), JITSymbolFlags::Exported}; |
263 | } |
264 | |
265 | if (NewSymbols.empty()) |
266 | return Error::success(); |
267 | |
268 | if (AddAbsoluteSymbols) |
269 | return AddAbsoluteSymbols(JD, std::move(NewSymbols)); |
270 | return JD.define(MU: absoluteSymbols(Symbols: std::move(NewSymbols))); |
271 | } |
272 | |
273 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
274 | StaticLibraryDefinitionGenerator::Load( |
275 | ObjectLayer &L, const char *FileName, |
276 | GetObjectFileInterface GetObjFileInterface) { |
277 | |
278 | auto B = object::createBinary(Path: FileName); |
279 | if (!B) |
280 | return createFileError(F: FileName, E: B.takeError()); |
281 | |
282 | // If this is a regular archive then create an instance from it. |
283 | if (isa<object::Archive>(Val: B->getBinary())) { |
284 | auto [Archive, ArchiveBuffer] = B->takeBinary(); |
285 | return Create(L, ArchiveBuffer: std::move(ArchiveBuffer), |
286 | Archive: std::unique_ptr<object::Archive>( |
287 | static_cast<object::Archive *>(Archive.release())), |
288 | GetObjFileInterface: std::move(GetObjFileInterface)); |
289 | } |
290 | |
291 | // If this is a universal binary then search for a slice matching the given |
292 | // Triple. |
293 | if (auto *UB = dyn_cast<object::MachOUniversalBinary>(Val: B->getBinary())) { |
294 | |
295 | const auto &TT = L.getExecutionSession().getTargetTriple(); |
296 | |
297 | auto SliceRange = getSliceRangeForArch(UB&: *UB, TT); |
298 | if (!SliceRange) |
299 | return SliceRange.takeError(); |
300 | |
301 | auto SliceBuffer = MemoryBuffer::getFileSlice(Filename: FileName, MapSize: SliceRange->second, |
302 | Offset: SliceRange->first); |
303 | if (!SliceBuffer) |
304 | return make_error<StringError>( |
305 | Args: Twine("Could not create buffer for " ) + TT.str() + " slice of " + |
306 | FileName + ": [ " + formatv(Fmt: "{0:x}" , Vals&: SliceRange->first) + " .. " + |
307 | formatv(Fmt: "{0:x}" , Vals: SliceRange->first + SliceRange->second) + ": " + |
308 | SliceBuffer.getError().message(), |
309 | Args: SliceBuffer.getError()); |
310 | |
311 | return Create(L, ArchiveBuffer: std::move(*SliceBuffer), GetObjFileInterface: std::move(GetObjFileInterface)); |
312 | } |
313 | |
314 | return make_error<StringError>(Args: Twine("Unrecognized file type for " ) + |
315 | FileName, |
316 | Args: inconvertibleErrorCode()); |
317 | } |
318 | |
319 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
320 | StaticLibraryDefinitionGenerator::Create( |
321 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
322 | std::unique_ptr<object::Archive> Archive, |
323 | GetObjectFileInterface GetObjFileInterface) { |
324 | |
325 | Error Err = Error::success(); |
326 | |
327 | std::unique_ptr<StaticLibraryDefinitionGenerator> ADG( |
328 | new StaticLibraryDefinitionGenerator( |
329 | L, std::move(ArchiveBuffer), std::move(Archive), |
330 | std::move(GetObjFileInterface), Err)); |
331 | |
332 | if (Err) |
333 | return std::move(Err); |
334 | |
335 | return std::move(ADG); |
336 | } |
337 | |
338 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
339 | StaticLibraryDefinitionGenerator::Create( |
340 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
341 | GetObjectFileInterface GetObjFileInterface) { |
342 | |
343 | auto B = object::createBinary(Source: ArchiveBuffer->getMemBufferRef()); |
344 | if (!B) |
345 | return B.takeError(); |
346 | |
347 | // If this is a regular archive then create an instance from it. |
348 | if (isa<object::Archive>(Val: *B)) |
349 | return Create(L, ArchiveBuffer: std::move(ArchiveBuffer), |
350 | Archive: std::unique_ptr<object::Archive>( |
351 | static_cast<object::Archive *>(B->release())), |
352 | GetObjFileInterface: std::move(GetObjFileInterface)); |
353 | |
354 | // If this is a universal binary then search for a slice matching the given |
355 | // Triple. |
356 | if (auto *UB = dyn_cast<object::MachOUniversalBinary>(Val: B->get())) { |
357 | |
358 | const auto &TT = L.getExecutionSession().getTargetTriple(); |
359 | |
360 | auto SliceRange = getSliceRangeForArch(UB&: *UB, TT); |
361 | if (!SliceRange) |
362 | return SliceRange.takeError(); |
363 | |
364 | MemoryBufferRef SliceRef( |
365 | StringRef(ArchiveBuffer->getBufferStart() + SliceRange->first, |
366 | SliceRange->second), |
367 | ArchiveBuffer->getBufferIdentifier()); |
368 | |
369 | auto Archive = object::Archive::create(Source: SliceRef); |
370 | if (!Archive) |
371 | return Archive.takeError(); |
372 | |
373 | return Create(L, ArchiveBuffer: std::move(ArchiveBuffer), Archive: std::move(*Archive), |
374 | GetObjFileInterface: std::move(GetObjFileInterface)); |
375 | } |
376 | |
377 | return make_error<StringError>(Args: Twine("Unrecognized file type for " ) + |
378 | ArchiveBuffer->getBufferIdentifier(), |
379 | Args: inconvertibleErrorCode()); |
380 | } |
381 | |
382 | Error StaticLibraryDefinitionGenerator::tryToGenerate( |
383 | LookupState &LS, LookupKind K, JITDylib &JD, |
384 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { |
385 | // Don't materialize symbols from static archives unless this is a static |
386 | // lookup. |
387 | if (K != LookupKind::Static) |
388 | return Error::success(); |
389 | |
390 | // Bail out early if we've already freed the archive. |
391 | if (!Archive) |
392 | return Error::success(); |
393 | |
394 | DenseSet<std::pair<StringRef, StringRef>> ChildBufferInfos; |
395 | |
396 | for (const auto &KV : Symbols) { |
397 | const auto &Name = KV.first; |
398 | if (!ObjectFilesMap.count(Val: Name)) |
399 | continue; |
400 | auto ChildBuffer = ObjectFilesMap[Name]; |
401 | ChildBufferInfos.insert( |
402 | V: {ChildBuffer.getBuffer(), ChildBuffer.getBufferIdentifier()}); |
403 | } |
404 | |
405 | for (auto ChildBufferInfo : ChildBufferInfos) { |
406 | MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, |
407 | ChildBufferInfo.second); |
408 | |
409 | auto I = GetObjFileInterface(L.getExecutionSession(), ChildBufferRef); |
410 | if (!I) |
411 | return I.takeError(); |
412 | |
413 | if (auto Err = L.add(JD, O: MemoryBuffer::getMemBuffer(Ref: ChildBufferRef, RequiresNullTerminator: false), |
414 | I: std::move(*I))) |
415 | return Err; |
416 | } |
417 | |
418 | return Error::success(); |
419 | } |
420 | |
421 | Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() { |
422 | DenseMap<uint64_t, MemoryBufferRef> MemoryBuffers; |
423 | DenseSet<uint64_t> Visited; |
424 | DenseSet<uint64_t> Excluded; |
425 | for (auto &S : Archive->symbols()) { |
426 | StringRef SymName = S.getName(); |
427 | auto Member = S.getMember(); |
428 | if (!Member) |
429 | return Member.takeError(); |
430 | auto DataOffset = Member->getDataOffset(); |
431 | if (!Visited.count(V: DataOffset)) { |
432 | Visited.insert(V: DataOffset); |
433 | auto Child = Member->getAsBinary(); |
434 | if (!Child) |
435 | return Child.takeError(); |
436 | if ((*Child)->isCOFFImportFile()) { |
437 | ImportedDynamicLibraries.insert(x: (*Child)->getFileName().str()); |
438 | Excluded.insert(V: DataOffset); |
439 | continue; |
440 | } |
441 | MemoryBuffers[DataOffset] = (*Child)->getMemoryBufferRef(); |
442 | } |
443 | if (!Excluded.count(V: DataOffset)) |
444 | ObjectFilesMap[L.getExecutionSession().intern(SymName)] = |
445 | MemoryBuffers[DataOffset]; |
446 | } |
447 | |
448 | return Error::success(); |
449 | } |
450 | |
451 | Expected<std::pair<size_t, size_t>> |
452 | StaticLibraryDefinitionGenerator::getSliceRangeForArch( |
453 | object::MachOUniversalBinary &UB, const Triple &TT) { |
454 | |
455 | for (const auto &Obj : UB.objects()) { |
456 | auto ObjTT = Obj.getTriple(); |
457 | if (ObjTT.getArch() == TT.getArch() && |
458 | ObjTT.getSubArch() == TT.getSubArch() && |
459 | (TT.getVendor() == Triple::UnknownVendor || |
460 | ObjTT.getVendor() == TT.getVendor())) { |
461 | // We found a match. Return the range for the slice. |
462 | return std::make_pair(x: Obj.getOffset(), y: Obj.getSize()); |
463 | } |
464 | } |
465 | |
466 | return make_error<StringError>(Args: Twine("Universal binary " ) + UB.getFileName() + |
467 | " does not contain a slice for " + |
468 | TT.str(), |
469 | Args: inconvertibleErrorCode()); |
470 | } |
471 | |
472 | StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( |
473 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
474 | std::unique_ptr<object::Archive> Archive, |
475 | GetObjectFileInterface GetObjFileInterface, Error &Err) |
476 | : L(L), GetObjFileInterface(std::move(GetObjFileInterface)), |
477 | ArchiveBuffer(std::move(ArchiveBuffer)), Archive(std::move(Archive)) { |
478 | ErrorAsOutParameter _(&Err); |
479 | if (!this->GetObjFileInterface) |
480 | this->GetObjFileInterface = getObjectFileInterface; |
481 | if (!Err) |
482 | Err = buildObjectFilesMap(); |
483 | } |
484 | |
485 | std::unique_ptr<DLLImportDefinitionGenerator> |
486 | DLLImportDefinitionGenerator::Create(ExecutionSession &ES, |
487 | ObjectLinkingLayer &L) { |
488 | return std::unique_ptr<DLLImportDefinitionGenerator>( |
489 | new DLLImportDefinitionGenerator(ES, L)); |
490 | } |
491 | |
492 | Error DLLImportDefinitionGenerator::tryToGenerate( |
493 | LookupState &LS, LookupKind K, JITDylib &JD, |
494 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { |
495 | JITDylibSearchOrder LinkOrder; |
496 | JD.withLinkOrderDo(F: [&](const JITDylibSearchOrder &LO) { |
497 | LinkOrder.reserve(n: LO.size()); |
498 | for (auto &KV : LO) { |
499 | if (KV.first == &JD) |
500 | continue; |
501 | LinkOrder.push_back(x: KV); |
502 | } |
503 | }); |
504 | |
505 | // FIXME: if regular symbol name start with __imp_ we have to issue lookup of |
506 | // both __imp_ and stripped name and use the lookup information to resolve the |
507 | // real symbol name. |
508 | SymbolLookupSet LookupSet; |
509 | DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols; |
510 | for (auto &KV : Symbols) { |
511 | StringRef Deinterned = *KV.first; |
512 | if (Deinterned.starts_with(Prefix: getImpPrefix())) |
513 | Deinterned = Deinterned.drop_front(N: StringRef(getImpPrefix()).size()); |
514 | // Don't degrade the required state |
515 | if (ToLookUpSymbols.count(Val: Deinterned) && |
516 | ToLookUpSymbols[Deinterned] == SymbolLookupFlags::RequiredSymbol) |
517 | continue; |
518 | ToLookUpSymbols[Deinterned] = KV.second; |
519 | } |
520 | |
521 | for (auto &KV : ToLookUpSymbols) |
522 | LookupSet.add(Name: ES.intern(SymName: KV.first), Flags: KV.second); |
523 | |
524 | auto Resolved = |
525 | ES.lookup(SearchOrder: LinkOrder, Symbols: LookupSet, K: LookupKind::DLSym, RequiredState: SymbolState::Resolved); |
526 | if (!Resolved) |
527 | return Resolved.takeError(); |
528 | |
529 | auto G = createStubsGraph(Resolved: *Resolved); |
530 | if (!G) |
531 | return G.takeError(); |
532 | return L.add(JD, G: std::move(*G)); |
533 | } |
534 | |
535 | Expected<unsigned> |
536 | DLLImportDefinitionGenerator::getTargetPointerSize(const Triple &TT) { |
537 | switch (TT.getArch()) { |
538 | case Triple::x86_64: |
539 | return 8; |
540 | default: |
541 | return make_error<StringError>( |
542 | Args: "architecture unsupported by DLLImportDefinitionGenerator" , |
543 | Args: inconvertibleErrorCode()); |
544 | } |
545 | } |
546 | |
547 | Expected<llvm::endianness> |
548 | DLLImportDefinitionGenerator::getEndianness(const Triple &TT) { |
549 | switch (TT.getArch()) { |
550 | case Triple::x86_64: |
551 | return llvm::endianness::little; |
552 | default: |
553 | return make_error<StringError>( |
554 | Args: "architecture unsupported by DLLImportDefinitionGenerator" , |
555 | Args: inconvertibleErrorCode()); |
556 | } |
557 | } |
558 | |
559 | Expected<std::unique_ptr<jitlink::LinkGraph>> |
560 | DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) { |
561 | Triple TT = ES.getTargetTriple(); |
562 | auto PointerSize = getTargetPointerSize(TT); |
563 | if (!PointerSize) |
564 | return PointerSize.takeError(); |
565 | auto Endianness = getEndianness(TT); |
566 | if (!Endianness) |
567 | return Endianness.takeError(); |
568 | |
569 | auto G = std::make_unique<jitlink::LinkGraph>( |
570 | args: "<DLLIMPORT_STUBS>" , args&: TT, args&: *PointerSize, args&: *Endianness, |
571 | args&: jitlink::getGenericEdgeKindName); |
572 | jitlink::Section &Sec = |
573 | G->createSection(Name: getSectionName(), Prot: MemProt::Read | MemProt::Exec); |
574 | |
575 | for (auto &KV : Resolved) { |
576 | jitlink::Symbol &Target = G->addAbsoluteSymbol( |
577 | Name: *KV.first, Address: KV.second.getAddress(), Size: *PointerSize, |
578 | L: jitlink::Linkage::Strong, S: jitlink::Scope::Local, IsLive: false); |
579 | |
580 | // Create __imp_ symbol |
581 | jitlink::Symbol &Ptr = |
582 | jitlink::x86_64::createAnonymousPointer(G&: *G, PointerSection&: Sec, InitialTarget: &Target); |
583 | auto NameCopy = G->allocateContent(Source: Twine(getImpPrefix()) + *KV.first); |
584 | StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size()); |
585 | Ptr.setName(NameCopyRef); |
586 | Ptr.setLinkage(jitlink::Linkage::Strong); |
587 | Ptr.setScope(jitlink::Scope::Default); |
588 | |
589 | // Create PLT stub |
590 | // FIXME: check PLT stub of data symbol is not accessed |
591 | jitlink::Block &StubBlock = |
592 | jitlink::x86_64::createPointerJumpStubBlock(G&: *G, StubSection&: Sec, PointerSymbol&: Ptr); |
593 | G->addDefinedSymbol(Content&: StubBlock, Offset: 0, Name: *KV.first, Size: StubBlock.getSize(), |
594 | L: jitlink::Linkage::Strong, S: jitlink::Scope::Default, IsCallable: true, |
595 | IsLive: false); |
596 | } |
597 | |
598 | return std::move(G); |
599 | } |
600 | |
601 | } // End namespace orc. |
602 | } // End namespace llvm. |
603 | |