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/ExecutionEngine/Orc/ObjectFileInterface.h"
12 #include "llvm/IR/Constants.h"
13 #include "llvm/IR/Function.h"
14 #include "llvm/IR/GlobalVariable.h"
15 #include "llvm/IR/Module.h"
16 #include "llvm/MC/TargetRegistry.h"
17 #include "llvm/Object/MachOUniversal.h"
18 #include "llvm/Support/FormatVariadic.h"
19 #include "llvm/Target/TargetMachine.h"
25 CtorDtorIterator::CtorDtorIterator(const GlobalVariable
*GV
, bool End
)
27 GV
? dyn_cast_or_null
<ConstantArray
>(GV
->getInitializer()) : nullptr),
28 I((InitList
&& End
) ? InitList
->getNumOperands() : 0) {
31 bool CtorDtorIterator::operator==(const CtorDtorIterator
&Other
) const {
32 assert(InitList
== Other
.InitList
&& "Incomparable iterators.");
36 bool CtorDtorIterator::operator!=(const CtorDtorIterator
&Other
) const {
37 return !(*this == Other
);
40 CtorDtorIterator
& CtorDtorIterator::operator++() {
45 CtorDtorIterator
CtorDtorIterator::operator++(int) {
46 CtorDtorIterator Temp
= *this;
51 CtorDtorIterator::Element
CtorDtorIterator::operator*() const {
52 ConstantStruct
*CS
= dyn_cast
<ConstantStruct
>(InitList
->getOperand(I
));
53 assert(CS
&& "Unrecognized type in llvm.global_ctors/llvm.global_dtors");
55 Constant
*FuncC
= CS
->getOperand(1);
56 Function
*Func
= nullptr;
58 // Extract function pointer, pulling off any casts.
60 if (Function
*F
= dyn_cast_or_null
<Function
>(FuncC
)) {
63 } else if (ConstantExpr
*CE
= dyn_cast_or_null
<ConstantExpr
>(FuncC
)) {
65 FuncC
= dyn_cast_or_null
<ConstantExpr
>(CE
->getOperand(0));
69 // This isn't anything we recognize. Bail out with Func left set to null.
74 auto *Priority
= cast
<ConstantInt
>(CS
->getOperand(0));
75 Value
*Data
= CS
->getNumOperands() == 3 ? CS
->getOperand(2) : nullptr;
76 if (Data
&& !isa
<GlobalValue
>(Data
))
78 return Element(Priority
->getZExtValue(), Func
, Data
);
81 iterator_range
<CtorDtorIterator
> getConstructors(const Module
&M
) {
82 const GlobalVariable
*CtorsList
= M
.getNamedGlobal("llvm.global_ctors");
83 return make_range(CtorDtorIterator(CtorsList
, false),
84 CtorDtorIterator(CtorsList
, true));
87 iterator_range
<CtorDtorIterator
> getDestructors(const Module
&M
) {
88 const GlobalVariable
*DtorsList
= M
.getNamedGlobal("llvm.global_dtors");
89 return make_range(CtorDtorIterator(DtorsList
, false),
90 CtorDtorIterator(DtorsList
, true));
93 bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue
&GV
) {
94 if (GV
.isDeclaration())
97 if (GV
.hasName() && (GV
.getName() == "llvm.global_ctors" ||
98 GV
.getName() == "llvm.global_dtors"))
101 if (ObjFmt
== Triple::MachO
) {
102 // FIXME: These section checks are too strict: We should match first and
103 // second word split by comma.
104 if (GV
.hasSection() &&
105 (GV
.getSection().startswith("__DATA,__objc_classlist") ||
106 GV
.getSection().startswith("__DATA,__objc_selrefs")))
113 void CtorDtorRunner::add(iterator_range
<CtorDtorIterator
> CtorDtors
) {
114 if (CtorDtors
.empty())
117 MangleAndInterner
Mangle(
118 JD
.getExecutionSession(),
119 (*CtorDtors
.begin()).Func
->getParent()->getDataLayout());
121 for (auto CtorDtor
: CtorDtors
) {
122 assert(CtorDtor
.Func
&& CtorDtor
.Func
->hasName() &&
123 "Ctor/Dtor function must be named to be runnable under the JIT");
125 // FIXME: Maybe use a symbol promoter here instead.
126 if (CtorDtor
.Func
->hasLocalLinkage()) {
127 CtorDtor
.Func
->setLinkage(GlobalValue::ExternalLinkage
);
128 CtorDtor
.Func
->setVisibility(GlobalValue::HiddenVisibility
);
131 if (CtorDtor
.Data
&& cast
<GlobalValue
>(CtorDtor
.Data
)->isDeclaration()) {
132 dbgs() << " Skipping because why now?\n";
136 CtorDtorsByPriority
[CtorDtor
.Priority
].push_back(
137 Mangle(CtorDtor
.Func
->getName()));
141 Error
CtorDtorRunner::run() {
142 using CtorDtorTy
= void (*)();
144 SymbolLookupSet LookupSet
;
145 for (auto &KV
: CtorDtorsByPriority
)
146 for (auto &Name
: KV
.second
)
148 assert(!LookupSet
.containsDuplicates() &&
149 "Ctor/Dtor list contains duplicates");
151 auto &ES
= JD
.getExecutionSession();
152 if (auto CtorDtorMap
= ES
.lookup(
153 makeJITDylibSearchOrder(&JD
, JITDylibLookupFlags::MatchAllSymbols
),
154 std::move(LookupSet
))) {
155 for (auto &KV
: CtorDtorsByPriority
) {
156 for (auto &Name
: KV
.second
) {
157 assert(CtorDtorMap
->count(Name
) && "No entry for Name");
158 auto CtorDtor
= reinterpret_cast<CtorDtorTy
>(
159 static_cast<uintptr_t>((*CtorDtorMap
)[Name
].getAddress()));
163 CtorDtorsByPriority
.clear();
164 return Error::success();
166 return CtorDtorMap
.takeError();
169 void LocalCXXRuntimeOverridesBase::runDestructors() {
170 auto& CXXDestructorDataPairs
= DSOHandleOverride
;
171 for (auto &P
: CXXDestructorDataPairs
)
173 CXXDestructorDataPairs
.clear();
176 int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor
,
179 auto& CXXDestructorDataPairs
=
180 *reinterpret_cast<CXXDestructorDataPairList
*>(DSOHandle
);
181 CXXDestructorDataPairs
.push_back(std::make_pair(Destructor
, Arg
));
185 Error
LocalCXXRuntimeOverrides::enable(JITDylib
&JD
,
186 MangleAndInterner
&Mangle
) {
187 SymbolMap RuntimeInterposes
;
188 RuntimeInterposes
[Mangle("__dso_handle")] =
189 JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride
),
190 JITSymbolFlags::Exported
);
191 RuntimeInterposes
[Mangle("__cxa_atexit")] =
192 JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride
),
193 JITSymbolFlags::Exported
);
195 return JD
.define(absoluteSymbols(std::move(RuntimeInterposes
)));
198 void ItaniumCXAAtExitSupport::registerAtExit(void (*F
)(void *), void *Ctx
,
200 std::lock_guard
<std::mutex
> Lock(AtExitsMutex
);
201 AtExitRecords
[DSOHandle
].push_back({F
, Ctx
});
204 void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle
) {
205 std::vector
<AtExitRecord
> AtExitsToRun
;
208 std::lock_guard
<std::mutex
> Lock(AtExitsMutex
);
209 auto I
= AtExitRecords
.find(DSOHandle
);
210 if (I
!= AtExitRecords
.end()) {
211 AtExitsToRun
= std::move(I
->second
);
212 AtExitRecords
.erase(I
);
216 while (!AtExitsToRun
.empty()) {
217 AtExitsToRun
.back().F(AtExitsToRun
.back().Ctx
);
218 AtExitsToRun
.pop_back();
222 DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator(
223 sys::DynamicLibrary Dylib
, char GlobalPrefix
, SymbolPredicate Allow
)
224 : Dylib(std::move(Dylib
)), Allow(std::move(Allow
)),
225 GlobalPrefix(GlobalPrefix
) {}
227 Expected
<std::unique_ptr
<DynamicLibrarySearchGenerator
>>
228 DynamicLibrarySearchGenerator::Load(const char *FileName
, char GlobalPrefix
,
229 SymbolPredicate Allow
) {
231 auto Lib
= sys::DynamicLibrary::getPermanentLibrary(FileName
, &ErrMsg
);
233 return make_error
<StringError
>(std::move(ErrMsg
), inconvertibleErrorCode());
234 return std::make_unique
<DynamicLibrarySearchGenerator
>(
235 std::move(Lib
), GlobalPrefix
, std::move(Allow
));
238 Error
DynamicLibrarySearchGenerator::tryToGenerate(
239 LookupState
&LS
, LookupKind K
, JITDylib
&JD
,
240 JITDylibLookupFlags JDLookupFlags
, const SymbolLookupSet
&Symbols
) {
241 orc::SymbolMap NewSymbols
;
243 bool HasGlobalPrefix
= (GlobalPrefix
!= '\0');
245 for (auto &KV
: Symbols
) {
246 auto &Name
= KV
.first
;
251 if (Allow
&& !Allow(Name
))
254 if (HasGlobalPrefix
&& (*Name
).front() != GlobalPrefix
)
257 std::string
Tmp((*Name
).data() + HasGlobalPrefix
,
258 (*Name
).size() - HasGlobalPrefix
);
259 if (void *Addr
= Dylib
.getAddressOfSymbol(Tmp
.c_str())) {
260 NewSymbols
[Name
] = JITEvaluatedSymbol(
261 static_cast<JITTargetAddress
>(reinterpret_cast<uintptr_t>(Addr
)),
262 JITSymbolFlags::Exported
);
266 if (NewSymbols
.empty())
267 return Error::success();
269 return JD
.define(absoluteSymbols(std::move(NewSymbols
)));
272 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
273 StaticLibraryDefinitionGenerator::Load(
274 ObjectLayer
&L
, const char *FileName
,
275 GetObjectFileInterface GetObjFileInterface
) {
276 auto ArchiveBuffer
= errorOrToExpected(MemoryBuffer::getFile(FileName
));
279 return ArchiveBuffer
.takeError();
281 return Create(L
, std::move(*ArchiveBuffer
), std::move(GetObjFileInterface
));
284 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
285 StaticLibraryDefinitionGenerator::Load(
286 ObjectLayer
&L
, const char *FileName
, const Triple
&TT
,
287 GetObjectFileInterface GetObjFileInterface
) {
289 auto B
= object::createBinary(FileName
);
291 return B
.takeError();
293 // If this is a regular archive then create an instance from it.
294 if (isa
<object::Archive
>(B
->getBinary()))
295 return Create(L
, std::move(B
->takeBinary().second
),
296 std::move(GetObjFileInterface
));
298 // If this is a universal binary then search for a slice matching the given
300 if (auto *UB
= cast
<object::MachOUniversalBinary
>(B
->getBinary())) {
301 for (const auto &Obj
: UB
->objects()) {
302 auto ObjTT
= Obj
.getTriple();
303 if (ObjTT
.getArch() == TT
.getArch() &&
304 ObjTT
.getSubArch() == TT
.getSubArch() &&
305 (TT
.getVendor() == Triple::UnknownVendor
||
306 ObjTT
.getVendor() == TT
.getVendor())) {
307 // We found a match. Create an instance from a buffer covering this
309 auto SliceBuffer
= MemoryBuffer::getFileSlice(FileName
, Obj
.getSize(),
312 return make_error
<StringError
>(
313 Twine("Could not create buffer for ") + TT
.str() + " slice of " +
314 FileName
+ ": [ " + formatv("{0:x}", Obj
.getOffset()) +
315 " .. " + formatv("{0:x}", Obj
.getOffset() + Obj
.getSize()) +
316 ": " + SliceBuffer
.getError().message(),
317 SliceBuffer
.getError());
318 return Create(L
, std::move(*SliceBuffer
),
319 std::move(GetObjFileInterface
));
323 return make_error
<StringError
>(Twine("Universal binary ") + FileName
+
324 " does not contain a slice for " +
326 inconvertibleErrorCode());
329 return make_error
<StringError
>(Twine("Unrecognized file type for ") +
331 inconvertibleErrorCode());
334 Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
335 StaticLibraryDefinitionGenerator::Create(
336 ObjectLayer
&L
, std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
,
337 GetObjectFileInterface GetObjFileInterface
) {
338 Error Err
= Error::success();
340 std::unique_ptr
<StaticLibraryDefinitionGenerator
> ADG(
341 new StaticLibraryDefinitionGenerator(
342 L
, std::move(ArchiveBuffer
), std::move(GetObjFileInterface
), Err
));
345 return std::move(Err
);
347 return std::move(ADG
);
350 Error
StaticLibraryDefinitionGenerator::tryToGenerate(
351 LookupState
&LS
, LookupKind K
, JITDylib
&JD
,
352 JITDylibLookupFlags JDLookupFlags
, const SymbolLookupSet
&Symbols
) {
354 // Don't materialize symbols from static archives unless this is a static
356 if (K
!= LookupKind::Static
)
357 return Error::success();
359 // Bail out early if we've already freed the archive.
361 return Error::success();
363 DenseSet
<std::pair
<StringRef
, StringRef
>> ChildBufferInfos
;
365 for (const auto &KV
: Symbols
) {
366 const auto &Name
= KV
.first
;
367 auto Child
= Archive
->findSym(*Name
);
369 return Child
.takeError();
372 auto ChildBuffer
= (*Child
)->getMemoryBufferRef();
374 return ChildBuffer
.takeError();
375 ChildBufferInfos
.insert(
376 {ChildBuffer
->getBuffer(), ChildBuffer
->getBufferIdentifier()});
379 for (auto ChildBufferInfo
: ChildBufferInfos
) {
380 MemoryBufferRef
ChildBufferRef(ChildBufferInfo
.first
,
381 ChildBufferInfo
.second
);
383 auto I
= GetObjFileInterface(L
.getExecutionSession(), ChildBufferRef
);
385 return I
.takeError();
387 if (auto Err
= L
.add(JD
, MemoryBuffer::getMemBuffer(ChildBufferRef
, false),
392 return Error::success();
395 StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
396 ObjectLayer
&L
, std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
,
397 GetObjectFileInterface GetObjFileInterface
, Error
&Err
)
398 : L(L
), GetObjFileInterface(std::move(GetObjFileInterface
)),
399 ArchiveBuffer(std::move(ArchiveBuffer
)),
400 Archive(std::make_unique
<object::Archive
>(*this->ArchiveBuffer
, Err
)) {
402 if (!this->GetObjFileInterface
)
403 this->GetObjFileInterface
= getObjectFileInterface
;
406 } // End namespace orc.
407 } // End namespace llvm.