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