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