1447762daSMichael J. Spencer //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// 2447762daSMichael J. Spencer // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6447762daSMichael J. Spencer // 7447762daSMichael J. Spencer //===----------------------------------------------------------------------===// 8447762daSMichael J. Spencer // 9cfe341f5SHans Wennborg // This file implements the operating system DynamicLibrary concept. 10447762daSMichael J. Spencer // 11447762daSMichael J. Spencer //===----------------------------------------------------------------------===// 12447762daSMichael J. Spencer 13447762daSMichael J. Spencer #include "llvm/Support/DynamicLibrary.h" 148a8cd2baSChandler Carruth #include "llvm-c/Support.h" 15ed0881b2SChandler Carruth #include "llvm/ADT/DenseSet.h" 165fdd2cbaSFrederich Munch #include "llvm/ADT/STLExtras.h" 17ed0881b2SChandler Carruth #include "llvm/ADT/StringMap.h" 18447762daSMichael J. Spencer #include "llvm/Config/config.h" 198a8cd2baSChandler Carruth #include "llvm/Support/ManagedStatic.h" 20ed0881b2SChandler Carruth #include "llvm/Support/Mutex.h" 21447762daSMichael J. Spencer #include <cstdio> 22447762daSMichael J. Spencer #include <cstring> 23c1db8cf9SFrederich Munch #include <vector> 24447762daSMichael J. Spencer 25c1db8cf9SFrederich Munch using namespace llvm; 26c1db8cf9SFrederich Munch using namespace llvm::sys; 27fd96d5e1SFrederich Munch 28c1db8cf9SFrederich Munch // All methods for HandleSet should be used holding SymbolsMutex. 29c1db8cf9SFrederich Munch class DynamicLibrary::HandleSet { 30c1db8cf9SFrederich Munch typedef std::vector<void *> HandleList; 31c1db8cf9SFrederich Munch HandleList Handles; 32c1db8cf9SFrederich Munch void *Process; 33c1db8cf9SFrederich Munch 34c1db8cf9SFrederich Munch public: 35c1db8cf9SFrederich Munch static void *DLOpen(const char *Filename, std::string *Err); 36c1db8cf9SFrederich Munch static void DLClose(void *Handle); 37c1db8cf9SFrederich Munch static void *DLSym(void *Handle, const char *Symbol); 38c1db8cf9SFrederich Munch 39c1db8cf9SFrederich Munch HandleSet() : Process(nullptr) {} 40c1db8cf9SFrederich Munch ~HandleSet(); 41c1db8cf9SFrederich Munch 42c1db8cf9SFrederich Munch HandleList::iterator Find(void *Handle) { 43c1db8cf9SFrederich Munch return std::find(Handles.begin(), Handles.end(), Handle); 4470c377a3SFrederich Munch } 45b8c236a6SFrederich Munch 46c1db8cf9SFrederich Munch bool Contains(void *Handle) { 47c1db8cf9SFrederich Munch return Handle == Process || Find(Handle) != Handles.end(); 48c1db8cf9SFrederich Munch } 49c1db8cf9SFrederich Munch 50c1db8cf9SFrederich Munch bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { 51712e8d29SNico Weber #ifdef _WIN32 52c1db8cf9SFrederich Munch assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); 53c1db8cf9SFrederich Munch #endif 54c1db8cf9SFrederich Munch 55c1db8cf9SFrederich Munch if (LLVM_LIKELY(!IsProcess)) { 56c1db8cf9SFrederich Munch if (Find(Handle) != Handles.end()) { 57c1db8cf9SFrederich Munch if (CanClose) 58c1db8cf9SFrederich Munch DLClose(Handle); 59c1db8cf9SFrederich Munch return false; 60c1db8cf9SFrederich Munch } 61c1db8cf9SFrederich Munch Handles.push_back(Handle); 62c1db8cf9SFrederich Munch } else { 63712e8d29SNico Weber #ifndef _WIN32 64c1db8cf9SFrederich Munch if (Process) { 65c1db8cf9SFrederich Munch if (CanClose) 66c1db8cf9SFrederich Munch DLClose(Process); 67c1db8cf9SFrederich Munch if (Process == Handle) 68c1db8cf9SFrederich Munch return false; 69c1db8cf9SFrederich Munch } 70c1db8cf9SFrederich Munch #endif 71c1db8cf9SFrederich Munch Process = Handle; 72c1db8cf9SFrederich Munch } 73c1db8cf9SFrederich Munch return true; 74c1db8cf9SFrederich Munch } 75c1db8cf9SFrederich Munch 765fdd2cbaSFrederich Munch void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 775fdd2cbaSFrederich Munch if (Order & SO_LoadOrder) { 785fdd2cbaSFrederich Munch for (void *Handle : Handles) { 795fdd2cbaSFrederich Munch if (void *Ptr = DLSym(Handle, Symbol)) 805fdd2cbaSFrederich Munch return Ptr; 815fdd2cbaSFrederich Munch } 825fdd2cbaSFrederich Munch } else { 835fdd2cbaSFrederich Munch for (void *Handle : llvm::reverse(Handles)) { 845fdd2cbaSFrederich Munch if (void *Ptr = DLSym(Handle, Symbol)) 855fdd2cbaSFrederich Munch return Ptr; 865fdd2cbaSFrederich Munch } 875fdd2cbaSFrederich Munch } 885fdd2cbaSFrederich Munch return nullptr; 895fdd2cbaSFrederich Munch } 905fdd2cbaSFrederich Munch 915fdd2cbaSFrederich Munch void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 925fdd2cbaSFrederich Munch assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && 935fdd2cbaSFrederich Munch "Invalid Ordering"); 945fdd2cbaSFrederich Munch 955fdd2cbaSFrederich Munch if (!Process || (Order & SO_LoadedFirst)) { 965fdd2cbaSFrederich Munch if (void *Ptr = LibLookup(Symbol, Order)) 975fdd2cbaSFrederich Munch return Ptr; 985fdd2cbaSFrederich Munch } 99c1db8cf9SFrederich Munch if (Process) { 1005fdd2cbaSFrederich Munch // Use OS facilities to search the current binary and all loaded libs. 101c1db8cf9SFrederich Munch if (void *Ptr = DLSym(Process, Symbol)) 102c1db8cf9SFrederich Munch return Ptr; 1035fdd2cbaSFrederich Munch 1045fdd2cbaSFrederich Munch // Search any libs that might have been skipped because of RTLD_LOCAL. 1055fdd2cbaSFrederich Munch if (Order & SO_LoadedLast) { 1065fdd2cbaSFrederich Munch if (void *Ptr = LibLookup(Symbol, Order)) 107c1db8cf9SFrederich Munch return Ptr; 108c1db8cf9SFrederich Munch } 109c1db8cf9SFrederich Munch } 110c1db8cf9SFrederich Munch return nullptr; 111c1db8cf9SFrederich Munch } 112c1db8cf9SFrederich Munch }; 113c1db8cf9SFrederich Munch 114c1db8cf9SFrederich Munch namespace { 115c1db8cf9SFrederich Munch // Collection of symbol name/value pairs to be searched prior to any libraries. 116c1db8cf9SFrederich Munch static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols; 117c1db8cf9SFrederich Munch // Collection of known library handles. 118c1db8cf9SFrederich Munch static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles; 119c1db8cf9SFrederich Munch // Lock for ExplicitSymbols and OpenedHandles. 120c1db8cf9SFrederich Munch static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex; 121c1db8cf9SFrederich Munch } 122fd96d5e1SFrederich Munch 123712e8d29SNico Weber #ifdef _WIN32 124447762daSMichael J. Spencer 125447762daSMichael J. Spencer #include "Windows/DynamicLibrary.inc" 126447762daSMichael J. Spencer 127447762daSMichael J. Spencer #else 128447762daSMichael J. Spencer 129c1db8cf9SFrederich Munch #include "Unix/DynamicLibrary.inc" 130a19917daSJordy Rose 131447762daSMichael J. Spencer #endif 132447762daSMichael J. Spencer 133c1db8cf9SFrederich Munch char DynamicLibrary::Invalid; 1345fdd2cbaSFrederich Munch DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder = 1355fdd2cbaSFrederich Munch DynamicLibrary::SO_Linker; 136c1db8cf9SFrederich Munch 137447762daSMichael J. Spencer namespace llvm { 138c1db8cf9SFrederich Munch void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { 139c1db8cf9SFrederich Munch return DoSearch(SymbolName); // DynamicLibrary.inc 140c1db8cf9SFrederich Munch } 141447762daSMichael J. Spencer } 142447762daSMichael J. Spencer 143c1db8cf9SFrederich Munch void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { 144c1db8cf9SFrederich Munch SmartScopedLock<true> Lock(*SymbolsMutex); 145c1db8cf9SFrederich Munch (*ExplicitSymbols)[SymbolName] = SymbolValue; 146c1db8cf9SFrederich Munch } 147c1db8cf9SFrederich Munch 148c1db8cf9SFrederich Munch DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, 149c1db8cf9SFrederich Munch std::string *Err) { 1508c3735e5SFrederich Munch // Force OpenedHandles to be added into the ManagedStatic list before any 1518c3735e5SFrederich Munch // ManagedStatic can be added from static constructors in HandleSet::DLOpen. 1528c3735e5SFrederich Munch HandleSet& HS = *OpenedHandles; 1538c3735e5SFrederich Munch 154c1db8cf9SFrederich Munch void *Handle = HandleSet::DLOpen(FileName, Err); 1558c3735e5SFrederich Munch if (Handle != &Invalid) { 1568c3735e5SFrederich Munch SmartScopedLock<true> Lock(*SymbolsMutex); 1578c3735e5SFrederich Munch HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); 1588c3735e5SFrederich Munch } 159c1db8cf9SFrederich Munch 160c1db8cf9SFrederich Munch return DynamicLibrary(Handle); 161c1db8cf9SFrederich Munch } 162c1db8cf9SFrederich Munch 163c1db8cf9SFrederich Munch DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, 164c1db8cf9SFrederich Munch std::string *Err) { 165c1db8cf9SFrederich Munch SmartScopedLock<true> Lock(*SymbolsMutex); 166c1db8cf9SFrederich Munch // If we've already loaded this library, tell the caller. 167c1db8cf9SFrederich Munch if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false)) 168c1db8cf9SFrederich Munch *Err = "Library already loaded"; 169c1db8cf9SFrederich Munch 170c1db8cf9SFrederich Munch return DynamicLibrary(Handle); 171c1db8cf9SFrederich Munch } 172c1db8cf9SFrederich Munch 173c1db8cf9SFrederich Munch void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { 174c1db8cf9SFrederich Munch if (!isValid()) 175c1db8cf9SFrederich Munch return nullptr; 176c1db8cf9SFrederich Munch return HandleSet::DLSym(Data, SymbolName); 177c1db8cf9SFrederich Munch } 178c1db8cf9SFrederich Munch 179c1db8cf9SFrederich Munch void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { 180c1db8cf9SFrederich Munch { 18157093e88SFilip Pizlo SmartScopedLock<true> Lock(*SymbolsMutex); 182a19917daSJordy Rose 183447762daSMichael J. Spencer // First check symbols added via AddSymbol(). 18457093e88SFilip Pizlo if (ExplicitSymbols.isConstructed()) { 185c1db8cf9SFrederich Munch StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName); 186447762daSMichael J. Spencer 187a19917daSJordy Rose if (i != ExplicitSymbols->end()) 188a19917daSJordy Rose return i->second; 189447762daSMichael J. Spencer } 190447762daSMichael J. Spencer 191447762daSMichael J. Spencer // Now search the libraries. 19259e5a644SVassil Vassilev if (OpenedHandles.isConstructed()) { 1935fdd2cbaSFrederich Munch if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder)) 194c1db8cf9SFrederich Munch return Ptr; 195447762daSMichael J. Spencer } 196447762daSMichael J. Spencer } 197447762daSMichael J. Spencer 198c1db8cf9SFrederich Munch return llvm::SearchForAddressOfSpecialSymbol(SymbolName); 199c1db8cf9SFrederich Munch } 20034ddbf1aSPeter Zotov 20134ddbf1aSPeter Zotov //===----------------------------------------------------------------------===// 20234ddbf1aSPeter Zotov // C API. 20334ddbf1aSPeter Zotov //===----------------------------------------------------------------------===// 20434ddbf1aSPeter Zotov 20534ddbf1aSPeter Zotov LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { 206671fe2eeSPeter Zotov return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); 20734ddbf1aSPeter Zotov } 208af79f3dbSEli Bendersky 209af79f3dbSEli Bendersky void *LLVMSearchForAddressOfSymbol(const char *symbolName) { 210af79f3dbSEli Bendersky return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName); 211af79f3dbSEli Bendersky } 212af79f3dbSEli Bendersky 213af79f3dbSEli Bendersky void LLVMAddSymbol(const char *symbolName, void *symbolValue) { 214af79f3dbSEli Bendersky return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); 215af79f3dbSEli Bendersky } 216