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