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 JITTargetMachineBuilder::JITTargetMachineBuilder(Triple TT) 23 : TT(std::move(TT)) {} 24 25 Expected<JITTargetMachineBuilder> JITTargetMachineBuilder::detectHost() { 26 return JITTargetMachineBuilder(Triple(sys::getProcessTriple())); 27 } 28 29 Expected<std::unique_ptr<TargetMachine>> 30 JITTargetMachineBuilder::createTargetMachine() { 31 if (!Arch.empty()) { 32 Triple::ArchType Type = Triple::getArchTypeForLLVMName(Arch); 33 34 if (Type == Triple::UnknownArch) 35 return make_error<StringError>(std::string("Unknown arch: ") + Arch, 36 inconvertibleErrorCode()); 37 } 38 39 std::string ErrMsg; 40 auto *TheTarget = TargetRegistry::lookupTarget(TT.getTriple(), ErrMsg); 41 if (!TheTarget) 42 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 43 44 auto *TM = 45 TheTarget->createTargetMachine(TT.getTriple(), CPU, Features.getString(), 46 Options, RM, CM, OptLevel, /*JIT*/ true); 47 if (!TM) 48 return make_error<StringError>("Could not allocate target machine", 49 inconvertibleErrorCode()); 50 51 return std::unique_ptr<TargetMachine>(TM); 52 } 53 54 JITTargetMachineBuilder &JITTargetMachineBuilder::addFeatures( 55 const std::vector<std::string> &FeatureVec) { 56 for (const auto &F : FeatureVec) 57 Features.AddFeature(F); 58 return *this; 59 } 60 61 CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End) 62 : InitList( 63 GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr), 64 I((InitList && End) ? InitList->getNumOperands() : 0) { 65 } 66 67 bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const { 68 assert(InitList == Other.InitList && "Incomparable iterators."); 69 return I == Other.I; 70 } 71 72 bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const { 73 return !(*this == Other); 74 } 75 76 CtorDtorIterator& CtorDtorIterator::operator++() { 77 ++I; 78 return *this; 79 } 80 81 CtorDtorIterator CtorDtorIterator::operator++(int) { 82 CtorDtorIterator Temp = *this; 83 ++I; 84 return Temp; 85 } 86 87 CtorDtorIterator::Element CtorDtorIterator::operator*() const { 88 ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); 89 assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors"); 90 91 Constant *FuncC = CS->getOperand(1); 92 Function *Func = nullptr; 93 94 // Extract function pointer, pulling off any casts. 95 while (FuncC) { 96 if (Function *F = dyn_cast_or_null<Function>(FuncC)) { 97 Func = F; 98 break; 99 } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { 100 if (CE->isCast()) 101 FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0)); 102 else 103 break; 104 } else { 105 // This isn't anything we recognize. Bail out with Func left set to null. 106 break; 107 } 108 } 109 110 ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); 111 Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; 112 if (Data && !isa<GlobalValue>(Data)) 113 Data = nullptr; 114 return Element(Priority->getZExtValue(), Func, Data); 115 } 116 117 iterator_range<CtorDtorIterator> getConstructors(const Module &M) { 118 const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors"); 119 return make_range(CtorDtorIterator(CtorsList, false), 120 CtorDtorIterator(CtorsList, true)); 121 } 122 123 iterator_range<CtorDtorIterator> getDestructors(const Module &M) { 124 const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors"); 125 return make_range(CtorDtorIterator(DtorsList, false), 126 CtorDtorIterator(DtorsList, true)); 127 } 128 129 void CtorDtorRunner2::add(iterator_range<CtorDtorIterator> CtorDtors) { 130 if (CtorDtors.begin() == CtorDtors.end()) 131 return; 132 133 MangleAndInterner Mangle( 134 JD.getExecutionSession(), 135 (*CtorDtors.begin()).Func->getParent()->getDataLayout()); 136 137 for (const auto &CtorDtor : CtorDtors) { 138 assert(CtorDtor.Func && CtorDtor.Func->hasName() && 139 "Ctor/Dtor function must be named to be runnable under the JIT"); 140 141 if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) { 142 dbgs() << " Skipping because why now?\n"; 143 continue; 144 } 145 146 CtorDtorsByPriority[CtorDtor.Priority].push_back( 147 Mangle(CtorDtor.Func->getName())); 148 } 149 } 150 151 Error CtorDtorRunner2::run() { 152 using CtorDtorTy = void (*)(); 153 154 SymbolNameSet Names; 155 156 for (auto &KV : CtorDtorsByPriority) { 157 for (auto &Name : KV.second) { 158 auto Added = Names.insert(Name).second; 159 (void)Added; 160 assert(Added && "Ctor/Dtor names clashed"); 161 } 162 } 163 164 if (auto CtorDtorMap = lookup({&JD}, std::move(Names))) { 165 for (auto &KV : CtorDtorsByPriority) { 166 for (auto &Name : KV.second) { 167 assert(CtorDtorMap->count(Name) && "No entry for Name"); 168 auto CtorDtor = reinterpret_cast<CtorDtorTy>( 169 static_cast<uintptr_t>((*CtorDtorMap)[Name].getAddress())); 170 CtorDtor(); 171 } 172 } 173 return Error::success(); 174 } else 175 return CtorDtorMap.takeError(); 176 177 CtorDtorsByPriority.clear(); 178 179 return Error::success(); 180 } 181 182 void LocalCXXRuntimeOverridesBase::runDestructors() { 183 auto& CXXDestructorDataPairs = DSOHandleOverride; 184 for (auto &P : CXXDestructorDataPairs) 185 P.first(P.second); 186 CXXDestructorDataPairs.clear(); 187 } 188 189 int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, 190 void *Arg, 191 void *DSOHandle) { 192 auto& CXXDestructorDataPairs = 193 *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); 194 CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg)); 195 return 0; 196 } 197 198 Error LocalCXXRuntimeOverrides2::enable(JITDylib &JD, 199 MangleAndInterner &Mangle) { 200 SymbolMap RuntimeInterposes( 201 {{Mangle("__dso_handle"), 202 JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride), 203 JITSymbolFlags::Exported)}, 204 {Mangle("__cxa_atexit"), 205 JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride), 206 JITSymbolFlags::Exported)}}); 207 208 return JD.define(absoluteSymbols(std::move(RuntimeInterposes))); 209 } 210 211 DynamicLibraryFallbackGenerator::DynamicLibraryFallbackGenerator( 212 sys::DynamicLibrary Dylib, const DataLayout &DL, SymbolPredicate Allow) 213 : Dylib(std::move(Dylib)), Allow(std::move(Allow)), 214 GlobalPrefix(DL.getGlobalPrefix()) {} 215 216 SymbolNameSet DynamicLibraryFallbackGenerator:: 217 operator()(JITDylib &JD, const SymbolNameSet &Names) { 218 orc::SymbolNameSet Added; 219 orc::SymbolMap NewSymbols; 220 221 bool HasGlobalPrefix = (GlobalPrefix != '\0'); 222 223 for (auto &Name : Names) { 224 if (!Allow(Name) || (*Name).empty()) 225 continue; 226 227 if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) 228 continue; 229 230 std::string Tmp((*Name).data() + (HasGlobalPrefix ? 1 : 0), (*Name).size()); 231 if (void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str())) { 232 Added.insert(Name); 233 NewSymbols[Name] = JITEvaluatedSymbol( 234 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Addr)), 235 JITSymbolFlags::Exported); 236 } 237 } 238 239 // Add any new symbols to JD. Since the fallback generator is only called for 240 // symbols that are not already defined, this will never trigger a duplicate 241 // definition error, so we can wrap this call in a 'cantFail'. 242 if (!NewSymbols.empty()) 243 cantFail(JD.define(absoluteSymbols(std::move(NewSymbols)))); 244 245 return Added; 246 } 247 248 } // End namespace orc. 249 } // End namespace llvm. 250