1 //===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
10 #include "llvm/ExecutionEngine/Orc/Layer.h"
11 #include "llvm/IR/Constants.h"
12 #include "llvm/IR/Function.h"
13 #include "llvm/IR/GlobalVariable.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Object/MachOUniversal.h"
16 #include "llvm/Support/FormatVariadic.h"
17 #include "llvm/Support/TargetRegistry.h"
18 #include "llvm/Target/TargetMachine.h"
24 CtorDtorIterator::CtorDtorIterator(const GlobalVariable
*GV
, bool End
)
26 GV
? dyn_cast_or_null
<ConstantArray
>(GV
->getInitializer()) : nullptr),
27 I((InitList
&& End
) ? InitList
->getNumOperands() : 0) {
30 bool CtorDtorIterator::operator==(const CtorDtorIterator
&Other
) const {
31 assert(InitList
== Other
.InitList
&& "Incomparable iterators.");
35 bool CtorDtorIterator::operator!=(const CtorDtorIterator
&Other
) const {
36 return !(*this == Other
);
39 CtorDtorIterator
& CtorDtorIterator::operator++() {
44 CtorDtorIterator
CtorDtorIterator::operator++(int) {
45 CtorDtorIterator Temp
= *this;
50 CtorDtorIterator::Element
CtorDtorIterator::operator*() const {
51 ConstantStruct
*CS
= dyn_cast
<ConstantStruct
>(InitList
->getOperand(I
));
52 assert(CS
&& "Unrecognized type in llvm.global_ctors/llvm.global_dtors");
54 Constant
*FuncC
= CS
->getOperand(1);
55 Function
*Func
= nullptr;
57 // Extract function pointer, pulling off any casts.
59 if (Function
*F
= dyn_cast_or_null
<Function
>(FuncC
)) {
62 } else if (ConstantExpr
*CE
= dyn_cast_or_null
<ConstantExpr
>(FuncC
)) {
64 FuncC
= dyn_cast_or_null
<ConstantExpr
>(CE
->getOperand(0));
68 // This isn't anything we recognize. Bail out with Func left set to null.
73 auto *Priority
= cast
<ConstantInt
>(CS
->getOperand(0));
74 Value
*Data
= CS
->getNumOperands() == 3 ? CS
->getOperand(2) : nullptr;
75 if (Data
&& !isa
<GlobalValue
>(Data
))
77 return Element(Priority
->getZExtValue(), Func
, Data
);
80 iterator_range
<CtorDtorIterator
> getConstructors(const Module
&M
) {
81 const GlobalVariable
*CtorsList
= M
.getNamedGlobal("llvm.global_ctors");
82 return make_range(CtorDtorIterator(CtorsList
, false),
83 CtorDtorIterator(CtorsList
, true));
86 iterator_range
<CtorDtorIterator
> getDestructors(const Module
&M
) {
87 const GlobalVariable
*DtorsList
= M
.getNamedGlobal("llvm.global_dtors");
88 return make_range(CtorDtorIterator(DtorsList
, false),
89 CtorDtorIterator(DtorsList
, true));
92 bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue
&GV
) {
93 if (GV
.isDeclaration())
96 if (GV
.hasName() && (GV
.getName() == "llvm.global_ctors" ||
97 GV
.getName() == "llvm.global_dtors"))
100 if (ObjFmt
== Triple::MachO
) {
101 // FIXME: These section checks are too strict: We should match first and
102 // second word split by comma.
103 if (GV
.hasSection() &&
104 (GV
.getSection().startswith("__DATA,__objc_classlist") ||
105 GV
.getSection().startswith("__DATA,__objc_selrefs")))
112 void CtorDtorRunner::add(iterator_range
<CtorDtorIterator
> CtorDtors
) {
113 if (CtorDtors
.empty())
116 MangleAndInterner
Mangle(
117 JD
.getExecutionSession(),
118 (*CtorDtors
.begin()).Func
->getParent()->getDataLayout());
120 for (auto CtorDtor
: CtorDtors
) {
121 assert(CtorDtor
.Func
&& CtorDtor
.Func
->hasName() &&
122 "Ctor/Dtor function must be named to be runnable under the JIT");
124 // FIXME: Maybe use a symbol promoter here instead.
125 if (CtorDtor
.Func
->hasLocalLinkage()) {
126 CtorDtor
.Func
->setLinkage(GlobalValue::ExternalLinkage
);
127 CtorDtor
.Func
->setVisibility(GlobalValue::HiddenVisibility
);
130 if (CtorDtor
.Data
&& cast
<GlobalValue
>(CtorDtor
.Data
)->isDeclaration()) {
131 dbgs() << " Skipping because why now?\n";
135 CtorDtorsByPriority
[CtorDtor
.Priority
].push_back(
136 Mangle(CtorDtor
.Func
->getName()));
140 Error
CtorDtorRunner::run() {
141 using CtorDtorTy
= void (*)();
143 SymbolLookupSet LookupSet
;
144 for (auto &KV
: CtorDtorsByPriority
)
145 for (auto &Name
: KV
.second
)
147 assert(!LookupSet
.containsDuplicates() &&
148 "Ctor/Dtor list contains duplicates");
150 auto &ES
= JD
.getExecutionSession();
151 if (auto CtorDtorMap
= ES
.lookup(
152 makeJITDylibSearchOrder(&JD
, JITDylibLookupFlags::MatchAllSymbols
),
153 std::move(LookupSet
))) {
154 for (auto &KV
: CtorDtorsByPriority
) {
155 for (auto &Name
: KV
.second
) {
156 assert(CtorDtorMap
->count(Name
) && "No entry for Name");
157 auto CtorDtor
= reinterpret_cast<CtorDtorTy
>(
158 static_cast<uintptr_t>((*CtorDtorMap
)[Name
].getAddress()));
162 CtorDtorsByPriority
.clear();
163 return Error::success();
165 return CtorDtorMap
.takeError();
168 void LocalCXXRuntimeOverridesBase::runDestructors() {
169 auto& CXXDestructorDataPairs
= DSOHandleOverride
;
170 for (auto &P
: CXXDestructorDataPairs
)
172 CXXDestructorDataPairs
.clear();
175 int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor
,
178 auto& CXXDestructorDataPairs
=
179 *reinterpret_cast<CXXDestructorDataPairList
*>(DSOHandle
);
180 CXXDestructorDataPairs
.push_back(std::make_pair(Destructor
, Arg
));
184 Error
LocalCXXRuntimeOverrides::enable(JITDylib
&JD
,
185 MangleAndInterner
&Mangle
) {
186 SymbolMap RuntimeInterposes
;
187 RuntimeInterposes
[Mangle("__dso_handle")] =
188 JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride
),
189 JITSymbolFlags::Exported
);
190 RuntimeInterposes
[Mangle("__cxa_atexit")] =
191 JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride
),
192 JITSymbolFlags::Exported
);
194 return JD
.define(absoluteSymbols(std::move(RuntimeInterposes
)));
197 void ItaniumCXAAtExitSupport::registerAtExit(void (*F
)(void *), void *Ctx
,
199 std::lock_guard
<std::mutex
> Lock(AtExitsMutex
);
200 AtExitRecords
[DSOHandle
].push_back({F
, Ctx
});
203 void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle
) {
204 std::vector
<AtExitRecord
> AtExitsToRun
;
207 std::lock_guard
<std::mutex
> Lock(AtExitsMutex
);
208 auto I
= AtExitRecords
.find(DSOHandle
);
209 if (I
!= AtExitRecords
.end()) {
210 AtExitsToRun
= std::move(I
->second
);
211 AtExitRecords
.erase(I
);
215 while (!AtExitsToRun
.empty()) {
216 AtExitsToRun
.back().F(AtExitsToRun
.back().Ctx
);
217 AtExitsToRun
.pop_back();
221 DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator(
222 sys::DynamicLibrary Dylib
, char GlobalPrefix
, SymbolPredicate Allow
)
223 : Dylib(std::move(Dylib
)), Allow(std::move(Allow
)),
224 GlobalPrefix(GlobalPrefix
) {}
226 Expected
<std::unique_ptr
<DynamicLibrarySearchGenerator
>>
227 DynamicLibrarySearchGenerator::Load(const char *FileName
, char GlobalPrefix
,
228 SymbolPredicate Allow
) {
230 auto Lib
= sys::DynamicLibrary::getPermanentLibrary(FileName
, &ErrMsg
);
232 return make_error
<StringError
>(std::move(ErrMsg
), inconvertibleErrorCode());
233 return std::make_unique
<DynamicLibrarySearchGenerator
>(
234 std::move(Lib
), GlobalPrefix
, std::move(Allow
));
237 Error
DynamicLibrarySearchGenerator::tryToGenerate(
238 LookupState
&LS
, LookupKind K
, JITDylib
&JD
,
239 JITDylibLookupFlags JDLookupFlags
, const SymbolLookupSet
&Symbols
) {
240 orc::SymbolMap NewSymbols
;
242 bool HasGlobalPrefix
= (GlobalPrefix
!= '\0');
244 for (auto &KV
: Symbols
) {
245 auto &Name
= KV
.first
;
250 if (Allow
&& !Allow(Name
))
253 if (HasGlobalPrefix
&& (*Name
).front() != GlobalPrefix
)
256 std::string
Tmp((*Name
).data() + HasGlobalPrefix
,
257 (*Name
).size() - HasGlobalPrefix
);
258 if (void *Addr
= Dylib
.getAddressOfSymbol(Tmp
.c_str())) {
259 NewSymbols
[Name
] = JITEvaluatedSymbol(
260 static_cast<JITTargetAddress
>(reinterpret_cast<uintptr_t>(Addr
)),
261 JITSymbolFlags::Exported
);
265 if (NewSymbols
.empty())
266 return Error::success();
268 return JD
.define(absoluteSymbols(std::move(NewSymbols
)));
271 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
272 StaticLibraryDefinitionGenerator::Load(ObjectLayer
&L
, const char *FileName
) {
273 auto ArchiveBuffer
= errorOrToExpected(MemoryBuffer::getFile(FileName
));
276 return ArchiveBuffer
.takeError();
278 return Create(L
, std::move(*ArchiveBuffer
));
281 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
282 StaticLibraryDefinitionGenerator::Load(ObjectLayer
&L
, const char *FileName
,
284 auto B
= object::createBinary(FileName
);
286 return B
.takeError();
288 // If this is a regular archive then create an instance from it.
289 if (isa
<object::Archive
>(B
->getBinary()))
290 return Create(L
, std::move(B
->takeBinary().second
));
292 // If this is a universal binary then search for a slice matching the given
294 if (auto *UB
= cast
<object::MachOUniversalBinary
>(B
->getBinary())) {
295 for (const auto &Obj
: UB
->objects()) {
296 auto ObjTT
= Obj
.getTriple();
297 if (ObjTT
.getArch() == TT
.getArch() &&
298 ObjTT
.getSubArch() == TT
.getSubArch() &&
299 (TT
.getVendor() == Triple::UnknownVendor
||
300 ObjTT
.getVendor() == TT
.getVendor())) {
301 // We found a match. Create an instance from a buffer covering this
303 auto SliceBuffer
= MemoryBuffer::getFileSlice(FileName
, Obj
.getSize(),
306 return make_error
<StringError
>(
307 Twine("Could not create buffer for ") + TT
.str() + " slice of " +
308 FileName
+ ": [ " + formatv("{0:x}", Obj
.getOffset()) +
309 " .. " + formatv("{0:x}", Obj
.getOffset() + Obj
.getSize()) +
310 ": " + SliceBuffer
.getError().message(),
311 SliceBuffer
.getError());
312 return Create(L
, std::move(*SliceBuffer
));
316 return make_error
<StringError
>(Twine("Universal binary ") + FileName
+
317 " does not contain a slice for " +
319 inconvertibleErrorCode());
322 return make_error
<StringError
>(Twine("Unrecognized file type for ") +
324 inconvertibleErrorCode());
327 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
328 StaticLibraryDefinitionGenerator::Create(
329 ObjectLayer
&L
, std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
) {
330 Error Err
= Error::success();
332 std::unique_ptr
<StaticLibraryDefinitionGenerator
> ADG(
333 new StaticLibraryDefinitionGenerator(L
, std::move(ArchiveBuffer
), Err
));
336 return std::move(Err
);
338 return std::move(ADG
);
341 Error
StaticLibraryDefinitionGenerator::tryToGenerate(
342 LookupState
&LS
, LookupKind K
, JITDylib
&JD
,
343 JITDylibLookupFlags JDLookupFlags
, const SymbolLookupSet
&Symbols
) {
345 // Don't materialize symbols from static archives unless this is a static
347 if (K
!= LookupKind::Static
)
348 return Error::success();
350 // Bail out early if we've already freed the archive.
352 return Error::success();
354 DenseSet
<std::pair
<StringRef
, StringRef
>> ChildBufferInfos
;
356 for (const auto &KV
: Symbols
) {
357 const auto &Name
= KV
.first
;
358 auto Child
= Archive
->findSym(*Name
);
360 return Child
.takeError();
363 auto ChildBuffer
= (*Child
)->getMemoryBufferRef();
365 return ChildBuffer
.takeError();
366 ChildBufferInfos
.insert(
367 {ChildBuffer
->getBuffer(), ChildBuffer
->getBufferIdentifier()});
370 for (auto ChildBufferInfo
: ChildBufferInfos
) {
371 MemoryBufferRef
ChildBufferRef(ChildBufferInfo
.first
,
372 ChildBufferInfo
.second
);
374 if (auto Err
= L
.add(JD
, MemoryBuffer::getMemBuffer(ChildBufferRef
, false)))
378 return Error::success();
381 StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
382 ObjectLayer
&L
, std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
, Error
&Err
)
383 : L(L
), ArchiveBuffer(std::move(ArchiveBuffer
)),
384 Archive(std::make_unique
<object::Archive
>(*this->ArchiveBuffer
, Err
)) {}
386 } // End namespace orc.
387 } // End namespace llvm.