1 //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the operating system DynamicLibrary concept. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Support/DynamicLibrary.h" 14 #include "llvm-c/Support.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/Config/config.h" 18 #include "llvm/Support/Mutex.h" 19 #include <vector> 20 21 using namespace llvm; 22 using namespace llvm::sys; 23 24 // All methods for HandleSet should be used holding SymbolsMutex. 25 class DynamicLibrary::HandleSet { 26 typedef std::vector<void *> HandleList; 27 HandleList Handles; 28 void *Process = nullptr; 29 30 public: 31 static void *DLOpen(const char *Filename, std::string *Err); 32 static void DLClose(void *Handle); 33 static void *DLSym(void *Handle, const char *Symbol); 34 35 HandleSet() = default; 36 ~HandleSet(); 37 38 HandleList::iterator Find(void *Handle) { return find(Handles, Handle); } 39 40 bool Contains(void *Handle) { 41 return Handle == Process || Find(Handle) != Handles.end(); 42 } 43 44 bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { 45 #ifdef _WIN32 46 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); 47 #endif 48 49 if (LLVM_LIKELY(!IsProcess)) { 50 if (Find(Handle) != Handles.end()) { 51 if (CanClose) 52 DLClose(Handle); 53 return false; 54 } 55 Handles.push_back(Handle); 56 } else { 57 #ifndef _WIN32 58 if (Process) { 59 if (CanClose) 60 DLClose(Process); 61 if (Process == Handle) 62 return false; 63 } 64 #endif 65 Process = Handle; 66 } 67 return true; 68 } 69 70 void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 71 if (Order & SO_LoadOrder) { 72 for (void *Handle : Handles) { 73 if (void *Ptr = DLSym(Handle, Symbol)) 74 return Ptr; 75 } 76 } else { 77 for (void *Handle : llvm::reverse(Handles)) { 78 if (void *Ptr = DLSym(Handle, Symbol)) 79 return Ptr; 80 } 81 } 82 return nullptr; 83 } 84 85 void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 86 assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && 87 "Invalid Ordering"); 88 89 if (!Process || (Order & SO_LoadedFirst)) { 90 if (void *Ptr = LibLookup(Symbol, Order)) 91 return Ptr; 92 } 93 if (Process) { 94 // Use OS facilities to search the current binary and all loaded libs. 95 if (void *Ptr = DLSym(Process, Symbol)) 96 return Ptr; 97 98 // Search any libs that might have been skipped because of RTLD_LOCAL. 99 if (Order & SO_LoadedLast) { 100 if (void *Ptr = LibLookup(Symbol, Order)) 101 return Ptr; 102 } 103 } 104 return nullptr; 105 } 106 }; 107 108 namespace { 109 110 struct Globals { 111 // Collection of symbol name/value pairs to be searched prior to any 112 // libraries. 113 llvm::StringMap<void *> ExplicitSymbols; 114 // Collection of known library handles. 115 DynamicLibrary::HandleSet OpenedHandles; 116 // Lock for ExplicitSymbols and OpenedHandles. 117 llvm::sys::SmartMutex<true> SymbolsMutex; 118 }; 119 120 Globals &getGlobals() { 121 static Globals G; 122 return G; 123 } 124 125 } // namespace 126 127 #ifdef _WIN32 128 129 #include "Windows/DynamicLibrary.inc" 130 131 #else 132 133 #include "Unix/DynamicLibrary.inc" 134 135 #endif 136 137 char DynamicLibrary::Invalid; 138 DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder = 139 DynamicLibrary::SO_Linker; 140 141 namespace llvm { 142 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { 143 return DoSearch(SymbolName); // DynamicLibrary.inc 144 } 145 } // namespace llvm 146 147 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { 148 auto &G = getGlobals(); 149 SmartScopedLock<true> Lock(G.SymbolsMutex); 150 G.ExplicitSymbols[SymbolName] = SymbolValue; 151 } 152 153 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, 154 std::string *Err) { 155 auto &G = getGlobals(); 156 void *Handle = HandleSet::DLOpen(FileName, Err); 157 if (Handle != &Invalid) { 158 SmartScopedLock<true> Lock(G.SymbolsMutex); 159 G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); 160 } 161 162 return DynamicLibrary(Handle); 163 } 164 165 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, 166 std::string *Err) { 167 auto &G = getGlobals(); 168 SmartScopedLock<true> Lock(G.SymbolsMutex); 169 // If we've already loaded this library, tell the caller. 170 if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false, 171 /*CanClose*/ false)) 172 *Err = "Library already loaded"; 173 174 return DynamicLibrary(Handle); 175 } 176 177 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { 178 if (!isValid()) 179 return nullptr; 180 return HandleSet::DLSym(Data, SymbolName); 181 } 182 183 void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { 184 { 185 auto &G = getGlobals(); 186 SmartScopedLock<true> Lock(G.SymbolsMutex); 187 188 // First check symbols added via AddSymbol(). 189 StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName); 190 191 if (i != G.ExplicitSymbols.end()) 192 return i->second; 193 194 // Now search the libraries. 195 if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder)) 196 return Ptr; 197 } 198 199 return llvm::SearchForAddressOfSpecialSymbol(SymbolName); 200 } 201 202 //===----------------------------------------------------------------------===// 203 // C API. 204 //===----------------------------------------------------------------------===// 205 206 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { 207 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); 208 } 209 210 void *LLVMSearchForAddressOfSymbol(const char *symbolName) { 211 return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName); 212 } 213 214 void LLVMAddSymbol(const char *symbolName, void *symbolValue) { 215 return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); 216 } 217