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 CtorDtorRunner2::add(iterator_range<CtorDtorIterator> CtorDtors) { 91 if (CtorDtors.begin() == CtorDtors.end()) 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 CtorDtorRunner2::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 if (auto CtorDtorMap = lookup({&JD}, std::move(Names))) { 132 for (auto &KV : CtorDtorsByPriority) { 133 for (auto &Name : KV.second) { 134 assert(CtorDtorMap->count(Name) && "No entry for Name"); 135 auto CtorDtor = reinterpret_cast<CtorDtorTy>( 136 static_cast<uintptr_t>((*CtorDtorMap)[Name].getAddress())); 137 CtorDtor(); 138 } 139 } 140 return Error::success(); 141 } else 142 return CtorDtorMap.takeError(); 143 144 CtorDtorsByPriority.clear(); 145 146 return Error::success(); 147 } 148 149 void LocalCXXRuntimeOverridesBase::runDestructors() { 150 auto& CXXDestructorDataPairs = DSOHandleOverride; 151 for (auto &P : CXXDestructorDataPairs) 152 P.first(P.second); 153 CXXDestructorDataPairs.clear(); 154 } 155 156 int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, 157 void *Arg, 158 void *DSOHandle) { 159 auto& CXXDestructorDataPairs = 160 *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); 161 CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg)); 162 return 0; 163 } 164 165 Error LocalCXXRuntimeOverrides2::enable(JITDylib &JD, 166 MangleAndInterner &Mangle) { 167 SymbolMap RuntimeInterposes( 168 {{Mangle("__dso_handle"), 169 JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride), 170 JITSymbolFlags::Exported)}, 171 {Mangle("__cxa_atexit"), 172 JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride), 173 JITSymbolFlags::Exported)}}); 174 175 return JD.define(absoluteSymbols(std::move(RuntimeInterposes))); 176 } 177 178 DynamicLibraryFallbackGenerator::DynamicLibraryFallbackGenerator( 179 sys::DynamicLibrary Dylib, const DataLayout &DL, SymbolPredicate Allow) 180 : Dylib(std::move(Dylib)), Allow(std::move(Allow)), 181 GlobalPrefix(DL.getGlobalPrefix()) {} 182 183 Expected<DynamicLibraryFallbackGenerator> DynamicLibraryFallbackGenerator::Load( 184 const char *FileName, const DataLayout &DL, SymbolPredicate Allow) { 185 std::string ErrMsg; 186 auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg); 187 if (!Lib.isValid()) 188 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 189 return DynamicLibraryFallbackGenerator(std::move(Lib), DL, std::move(Allow)); 190 } 191 192 SymbolNameSet DynamicLibraryFallbackGenerator:: 193 operator()(JITDylib &JD, const SymbolNameSet &Names) { 194 orc::SymbolNameSet Added; 195 orc::SymbolMap NewSymbols; 196 197 bool HasGlobalPrefix = (GlobalPrefix != '\0'); 198 199 for (auto &Name : Names) { 200 if (!Allow(Name) || (*Name).empty()) 201 continue; 202 203 if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) 204 continue; 205 206 std::string Tmp((*Name).data() + (HasGlobalPrefix ? 1 : 0), (*Name).size()); 207 if (void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str())) { 208 Added.insert(Name); 209 NewSymbols[Name] = JITEvaluatedSymbol( 210 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Addr)), 211 JITSymbolFlags::Exported); 212 } 213 } 214 215 // Add any new symbols to JD. Since the fallback generator is only called for 216 // symbols that are not already defined, this will never trigger a duplicate 217 // definition error, so we can wrap this call in a 'cantFail'. 218 if (!NewSymbols.empty()) 219 cantFail(JD.define(absoluteSymbols(std::move(NewSymbols)))); 220 221 return Added; 222 } 223 224 } // End namespace orc. 225 } // End namespace llvm. 226