xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
12*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
13*0b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
14*0b57cec5SDimitry Andric #include "llvm/IR/Module.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h"
16*0b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric namespace llvm {
19*0b57cec5SDimitry Andric namespace orc {
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)
22*0b57cec5SDimitry Andric   : InitList(
23*0b57cec5SDimitry Andric       GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr),
24*0b57cec5SDimitry Andric     I((InitList && End) ? InitList->getNumOperands() : 0) {
25*0b57cec5SDimitry Andric }
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const {
28*0b57cec5SDimitry Andric   assert(InitList == Other.InitList && "Incomparable iterators.");
29*0b57cec5SDimitry Andric   return I == Other.I;
30*0b57cec5SDimitry Andric }
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const {
33*0b57cec5SDimitry Andric   return !(*this == Other);
34*0b57cec5SDimitry Andric }
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric CtorDtorIterator& CtorDtorIterator::operator++() {
37*0b57cec5SDimitry Andric   ++I;
38*0b57cec5SDimitry Andric   return *this;
39*0b57cec5SDimitry Andric }
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric CtorDtorIterator CtorDtorIterator::operator++(int) {
42*0b57cec5SDimitry Andric   CtorDtorIterator Temp = *this;
43*0b57cec5SDimitry Andric   ++I;
44*0b57cec5SDimitry Andric   return Temp;
45*0b57cec5SDimitry Andric }
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric CtorDtorIterator::Element CtorDtorIterator::operator*() const {
48*0b57cec5SDimitry Andric   ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I));
49*0b57cec5SDimitry Andric   assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors");
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   Constant *FuncC = CS->getOperand(1);
52*0b57cec5SDimitry Andric   Function *Func = nullptr;
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric   // Extract function pointer, pulling off any casts.
55*0b57cec5SDimitry Andric   while (FuncC) {
56*0b57cec5SDimitry Andric     if (Function *F = dyn_cast_or_null<Function>(FuncC)) {
57*0b57cec5SDimitry Andric       Func = F;
58*0b57cec5SDimitry Andric       break;
59*0b57cec5SDimitry Andric     } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) {
60*0b57cec5SDimitry Andric       if (CE->isCast())
61*0b57cec5SDimitry Andric         FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0));
62*0b57cec5SDimitry Andric       else
63*0b57cec5SDimitry Andric         break;
64*0b57cec5SDimitry Andric     } else {
65*0b57cec5SDimitry Andric       // This isn't anything we recognize. Bail out with Func left set to null.
66*0b57cec5SDimitry Andric       break;
67*0b57cec5SDimitry Andric     }
68*0b57cec5SDimitry Andric   }
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric   ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
71*0b57cec5SDimitry Andric   Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr;
72*0b57cec5SDimitry Andric   if (Data && !isa<GlobalValue>(Data))
73*0b57cec5SDimitry Andric     Data = nullptr;
74*0b57cec5SDimitry Andric   return Element(Priority->getZExtValue(), Func, Data);
75*0b57cec5SDimitry Andric }
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric iterator_range<CtorDtorIterator> getConstructors(const Module &M) {
78*0b57cec5SDimitry Andric   const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors");
79*0b57cec5SDimitry Andric   return make_range(CtorDtorIterator(CtorsList, false),
80*0b57cec5SDimitry Andric                     CtorDtorIterator(CtorsList, true));
81*0b57cec5SDimitry Andric }
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric iterator_range<CtorDtorIterator> getDestructors(const Module &M) {
84*0b57cec5SDimitry Andric   const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors");
85*0b57cec5SDimitry Andric   return make_range(CtorDtorIterator(DtorsList, false),
86*0b57cec5SDimitry Andric                     CtorDtorIterator(DtorsList, true));
87*0b57cec5SDimitry Andric }
88*0b57cec5SDimitry Andric 
89*0b57cec5SDimitry Andric void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) {
90*0b57cec5SDimitry Andric   if (empty(CtorDtors))
91*0b57cec5SDimitry Andric     return;
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric   MangleAndInterner Mangle(
94*0b57cec5SDimitry Andric       JD.getExecutionSession(),
95*0b57cec5SDimitry Andric       (*CtorDtors.begin()).Func->getParent()->getDataLayout());
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   for (const auto &CtorDtor : CtorDtors) {
98*0b57cec5SDimitry Andric     assert(CtorDtor.Func && CtorDtor.Func->hasName() &&
99*0b57cec5SDimitry Andric            "Ctor/Dtor function must be named to be runnable under the JIT");
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric     // FIXME: Maybe use a symbol promoter here instead.
102*0b57cec5SDimitry Andric     if (CtorDtor.Func->hasLocalLinkage()) {
103*0b57cec5SDimitry Andric       CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage);
104*0b57cec5SDimitry Andric       CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility);
105*0b57cec5SDimitry Andric     }
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric     if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) {
108*0b57cec5SDimitry Andric       dbgs() << "  Skipping because why now?\n";
109*0b57cec5SDimitry Andric       continue;
110*0b57cec5SDimitry Andric     }
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric     CtorDtorsByPriority[CtorDtor.Priority].push_back(
113*0b57cec5SDimitry Andric         Mangle(CtorDtor.Func->getName()));
114*0b57cec5SDimitry Andric   }
115*0b57cec5SDimitry Andric }
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric Error CtorDtorRunner::run() {
118*0b57cec5SDimitry Andric   using CtorDtorTy = void (*)();
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   SymbolNameSet Names;
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   for (auto &KV : CtorDtorsByPriority) {
123*0b57cec5SDimitry Andric     for (auto &Name : KV.second) {
124*0b57cec5SDimitry Andric       auto Added = Names.insert(Name).second;
125*0b57cec5SDimitry Andric       (void)Added;
126*0b57cec5SDimitry Andric       assert(Added && "Ctor/Dtor names clashed");
127*0b57cec5SDimitry Andric     }
128*0b57cec5SDimitry Andric   }
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric   auto &ES = JD.getExecutionSession();
131*0b57cec5SDimitry Andric   if (auto CtorDtorMap =
132*0b57cec5SDimitry Andric           ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names))) {
133*0b57cec5SDimitry Andric     for (auto &KV : CtorDtorsByPriority) {
134*0b57cec5SDimitry Andric       for (auto &Name : KV.second) {
135*0b57cec5SDimitry Andric         assert(CtorDtorMap->count(Name) && "No entry for Name");
136*0b57cec5SDimitry Andric         auto CtorDtor = reinterpret_cast<CtorDtorTy>(
137*0b57cec5SDimitry Andric             static_cast<uintptr_t>((*CtorDtorMap)[Name].getAddress()));
138*0b57cec5SDimitry Andric         CtorDtor();
139*0b57cec5SDimitry Andric       }
140*0b57cec5SDimitry Andric     }
141*0b57cec5SDimitry Andric     CtorDtorsByPriority.clear();
142*0b57cec5SDimitry Andric     return Error::success();
143*0b57cec5SDimitry Andric   } else
144*0b57cec5SDimitry Andric     return CtorDtorMap.takeError();
145*0b57cec5SDimitry Andric }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric void LocalCXXRuntimeOverridesBase::runDestructors() {
148*0b57cec5SDimitry Andric   auto& CXXDestructorDataPairs = DSOHandleOverride;
149*0b57cec5SDimitry Andric   for (auto &P : CXXDestructorDataPairs)
150*0b57cec5SDimitry Andric     P.first(P.second);
151*0b57cec5SDimitry Andric   CXXDestructorDataPairs.clear();
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor,
155*0b57cec5SDimitry Andric                                                     void *Arg,
156*0b57cec5SDimitry Andric                                                     void *DSOHandle) {
157*0b57cec5SDimitry Andric   auto& CXXDestructorDataPairs =
158*0b57cec5SDimitry Andric     *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle);
159*0b57cec5SDimitry Andric   CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg));
160*0b57cec5SDimitry Andric   return 0;
161*0b57cec5SDimitry Andric }
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric Error LocalCXXRuntimeOverrides::enable(JITDylib &JD,
164*0b57cec5SDimitry Andric                                         MangleAndInterner &Mangle) {
165*0b57cec5SDimitry Andric   SymbolMap RuntimeInterposes;
166*0b57cec5SDimitry Andric   RuntimeInterposes[Mangle("__dso_handle")] =
167*0b57cec5SDimitry Andric     JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride),
168*0b57cec5SDimitry Andric                        JITSymbolFlags::Exported);
169*0b57cec5SDimitry Andric   RuntimeInterposes[Mangle("__cxa_atexit")] =
170*0b57cec5SDimitry Andric     JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride),
171*0b57cec5SDimitry Andric                        JITSymbolFlags::Exported);
172*0b57cec5SDimitry Andric 
173*0b57cec5SDimitry Andric   return JD.define(absoluteSymbols(std::move(RuntimeInterposes)));
174*0b57cec5SDimitry Andric }
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator(
177*0b57cec5SDimitry Andric     sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow)
178*0b57cec5SDimitry Andric     : Dylib(std::move(Dylib)), Allow(std::move(Allow)),
179*0b57cec5SDimitry Andric       GlobalPrefix(GlobalPrefix) {}
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric Expected<DynamicLibrarySearchGenerator>
182*0b57cec5SDimitry Andric DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix,
183*0b57cec5SDimitry Andric                                     SymbolPredicate Allow) {
184*0b57cec5SDimitry Andric   std::string ErrMsg;
185*0b57cec5SDimitry Andric   auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg);
186*0b57cec5SDimitry Andric   if (!Lib.isValid())
187*0b57cec5SDimitry Andric     return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
188*0b57cec5SDimitry Andric   return DynamicLibrarySearchGenerator(std::move(Lib), GlobalPrefix,
189*0b57cec5SDimitry Andric                                        std::move(Allow));
190*0b57cec5SDimitry Andric }
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric Expected<SymbolNameSet>
193*0b57cec5SDimitry Andric DynamicLibrarySearchGenerator::operator()(JITDylib &JD,
194*0b57cec5SDimitry Andric                                           const SymbolNameSet &Names) {
195*0b57cec5SDimitry Andric   orc::SymbolNameSet Added;
196*0b57cec5SDimitry Andric   orc::SymbolMap NewSymbols;
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric   bool HasGlobalPrefix = (GlobalPrefix != '\0');
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric   for (auto &Name : Names) {
201*0b57cec5SDimitry Andric     if ((*Name).empty())
202*0b57cec5SDimitry Andric       continue;
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric     if (Allow && !Allow(Name))
205*0b57cec5SDimitry Andric       continue;
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric     if (HasGlobalPrefix && (*Name).front() != GlobalPrefix)
208*0b57cec5SDimitry Andric       continue;
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric     std::string Tmp((*Name).data() + HasGlobalPrefix,
211*0b57cec5SDimitry Andric                     (*Name).size() - HasGlobalPrefix);
212*0b57cec5SDimitry Andric     if (void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str())) {
213*0b57cec5SDimitry Andric       Added.insert(Name);
214*0b57cec5SDimitry Andric       NewSymbols[Name] = JITEvaluatedSymbol(
215*0b57cec5SDimitry Andric           static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Addr)),
216*0b57cec5SDimitry Andric           JITSymbolFlags::Exported);
217*0b57cec5SDimitry Andric     }
218*0b57cec5SDimitry Andric   }
219*0b57cec5SDimitry Andric 
220*0b57cec5SDimitry Andric   // Add any new symbols to JD. Since the generator is only called for symbols
221*0b57cec5SDimitry Andric   // that are not already defined, this will never trigger a duplicate
222*0b57cec5SDimitry Andric   // definition error, so we can wrap this call in a 'cantFail'.
223*0b57cec5SDimitry Andric   if (!NewSymbols.empty())
224*0b57cec5SDimitry Andric     cantFail(JD.define(absoluteSymbols(std::move(NewSymbols))));
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric   return Added;
227*0b57cec5SDimitry Andric }
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric } // End namespace orc.
230*0b57cec5SDimitry Andric } // End namespace llvm.
231