151c0b2f7Stbbdev /* 2*4bb2faa0Ssarathnandu Copyright (c) 2005-2023 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev #include "dynamic_link.h" 18*4bb2faa0Ssarathnandu #include "environment.h" 1951c0b2f7Stbbdev 2049e08aacStbbdev #include "oneapi/tbb/detail/_template_helpers.h" 2149e08aacStbbdev #include "oneapi/tbb/detail/_utils.h" 2251c0b2f7Stbbdev 2351c0b2f7Stbbdev /* 2451c0b2f7Stbbdev This file is used by both TBB and OpenMP RTL. Do not use __TBB_ASSERT() macro 2551c0b2f7Stbbdev and runtime_warning() function because they are not available in OpenMP. Use 2651c0b2f7Stbbdev __TBB_ASSERT_EX and DYNAMIC_LINK_WARNING instead. 2751c0b2f7Stbbdev */ 2851c0b2f7Stbbdev 2951c0b2f7Stbbdev #include <cstdarg> // va_list etc. 308827ea7dSLong Nguyen #include <cstring> // strrchr 3151c0b2f7Stbbdev #if _WIN32 3251c0b2f7Stbbdev #include <malloc.h> 3351c0b2f7Stbbdev 3451c0b2f7Stbbdev // Unify system calls 3551c0b2f7Stbbdev #define dlopen( name, flags ) LoadLibrary( name ) 3651c0b2f7Stbbdev #define dlsym( handle, name ) GetProcAddress( handle, name ) 3751c0b2f7Stbbdev #define dlclose( handle ) ( ! FreeLibrary( handle ) ) 3851c0b2f7Stbbdev #define dlerror() GetLastError() 3951c0b2f7Stbbdev #ifndef PATH_MAX 4051c0b2f7Stbbdev #define PATH_MAX MAX_PATH 4151c0b2f7Stbbdev #endif 4251c0b2f7Stbbdev #else /* _WIN32 */ 4351c0b2f7Stbbdev #include <dlfcn.h> 4451c0b2f7Stbbdev #include <unistd.h> 4551c0b2f7Stbbdev 4651c0b2f7Stbbdev #include <climits> 4751c0b2f7Stbbdev #include <cstdlib> 4851c0b2f7Stbbdev #endif /* _WIN32 */ 4951c0b2f7Stbbdev 5051c0b2f7Stbbdev #if __TBB_WEAK_SYMBOLS_PRESENT && !__TBB_DYNAMIC_LOAD_ENABLED 5151c0b2f7Stbbdev //TODO: use function attribute for weak symbols instead of the pragma. 5251c0b2f7Stbbdev #pragma weak dlopen 5351c0b2f7Stbbdev #pragma weak dlsym 5451c0b2f7Stbbdev #pragma weak dlclose 5551c0b2f7Stbbdev #endif /* __TBB_WEAK_SYMBOLS_PRESENT && !__TBB_DYNAMIC_LOAD_ENABLED */ 5651c0b2f7Stbbdev 5751c0b2f7Stbbdev 5851c0b2f7Stbbdev #define __USE_STATIC_DL_INIT ( !__ANDROID__ ) 5951c0b2f7Stbbdev 6051c0b2f7Stbbdev 6151c0b2f7Stbbdev /* 6251c0b2f7Stbbdev dynamic_link is a common interface for searching for required symbols in an 6351c0b2f7Stbbdev executable and dynamic libraries. 6451c0b2f7Stbbdev 6551c0b2f7Stbbdev dynamic_link provides certain guarantees: 6651c0b2f7Stbbdev 1. Either all or none of the requested symbols are resolved. Moreover, if 6751c0b2f7Stbbdev symbols are not resolved, the dynamic_link_descriptor table is not modified; 6851c0b2f7Stbbdev 2. All returned symbols have secured lifetime: this means that none of them 6951c0b2f7Stbbdev can be invalidated until dynamic_unlink is called; 7051c0b2f7Stbbdev 3. Any loaded library is loaded only via the full path. The full path is that 7151c0b2f7Stbbdev from which the runtime itself was loaded. (This is done to avoid security 7251c0b2f7Stbbdev issues caused by loading libraries from insecure paths). 7351c0b2f7Stbbdev 7451c0b2f7Stbbdev dynamic_link searches for the requested symbols in three stages, stopping as 7551c0b2f7Stbbdev soon as all of the symbols have been resolved. 7651c0b2f7Stbbdev 7751c0b2f7Stbbdev 1. Search the global scope: 7851c0b2f7Stbbdev a. On Windows: dynamic_link tries to obtain the handle of the requested 7951c0b2f7Stbbdev library and if it succeeds it resolves the symbols via that handle. 8051c0b2f7Stbbdev b. On Linux: dynamic_link tries to search for the symbols in the global 8151c0b2f7Stbbdev scope via the main program handle. If the symbols are present in the global 8251c0b2f7Stbbdev scope their lifetime is not guaranteed (since dynamic_link does not know 8351c0b2f7Stbbdev anything about the library from which they are exported). Therefore it 8451c0b2f7Stbbdev tries to "pin" the symbols by obtaining the library name and reopening it. 8551c0b2f7Stbbdev dlopen may fail to reopen the library in two cases: 8651c0b2f7Stbbdev i. The symbols are exported from the executable. Currently dynamic _link 8751c0b2f7Stbbdev cannot handle this situation, so it will not find these symbols in this 8851c0b2f7Stbbdev step. 8951c0b2f7Stbbdev ii. The necessary library has been unloaded and cannot be reloaded. It 9051c0b2f7Stbbdev seems there is nothing that can be done in this case. No symbols are 9151c0b2f7Stbbdev returned. 9251c0b2f7Stbbdev 9351c0b2f7Stbbdev 2. Dynamic load: an attempt is made to load the requested library via the 9451c0b2f7Stbbdev full path. 9551c0b2f7Stbbdev The full path used is that from which the runtime itself was loaded. If the 9651c0b2f7Stbbdev library can be loaded, then an attempt is made to resolve the requested 9751c0b2f7Stbbdev symbols in the newly loaded library. 9851c0b2f7Stbbdev If the symbols are not found the library is unloaded. 9951c0b2f7Stbbdev 10051c0b2f7Stbbdev 3. Weak symbols: if weak symbols are available they are returned. 10151c0b2f7Stbbdev */ 10251c0b2f7Stbbdev 10351c0b2f7Stbbdev namespace tbb { 10451c0b2f7Stbbdev namespace detail { 10551c0b2f7Stbbdev namespace r1 { 10651c0b2f7Stbbdev 10751c0b2f7Stbbdev #if __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED 10851c0b2f7Stbbdev 10951c0b2f7Stbbdev #if !defined(DYNAMIC_LINK_WARNING) && !__TBB_WIN8UI_SUPPORT && __TBB_DYNAMIC_LOAD_ENABLED 11051c0b2f7Stbbdev // Report runtime errors and continue. 11151c0b2f7Stbbdev #define DYNAMIC_LINK_WARNING dynamic_link_warning dynamic_link_warning(dynamic_link_error_t code,...)11251c0b2f7Stbbdev static void dynamic_link_warning( dynamic_link_error_t code, ... ) { 11351c0b2f7Stbbdev suppress_unused_warning(code); 11451c0b2f7Stbbdev } // library_warning 11551c0b2f7Stbbdev #endif /* !defined(DYNAMIC_LINK_WARNING) && !__TBB_WIN8UI_SUPPORT && __TBB_DYNAMIC_LOAD_ENABLED */ 11651c0b2f7Stbbdev resolve_symbols(dynamic_link_handle module,const dynamic_link_descriptor descriptors[],std::size_t required)11751c0b2f7Stbbdev static bool resolve_symbols( dynamic_link_handle module, const dynamic_link_descriptor descriptors[], std::size_t required ) 11851c0b2f7Stbbdev { 11951c0b2f7Stbbdev if ( !module ) 12051c0b2f7Stbbdev return false; 12151c0b2f7Stbbdev 12251c0b2f7Stbbdev #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */ 12351c0b2f7Stbbdev if ( !dlsym ) return false; 12451c0b2f7Stbbdev #endif /* !__TBB_DYNAMIC_LOAD_ENABLED */ 12551c0b2f7Stbbdev 12651c0b2f7Stbbdev const std::size_t n_desc=20; // Usually we don't have more than 20 descriptors per library 12751c0b2f7Stbbdev __TBB_ASSERT_EX( required <= n_desc, "Too many descriptors is required" ); 12851c0b2f7Stbbdev if ( required > n_desc ) return false; 12951c0b2f7Stbbdev pointer_to_handler h[n_desc]; 13051c0b2f7Stbbdev 13151c0b2f7Stbbdev for ( std::size_t k = 0; k < required; ++k ) { 13251c0b2f7Stbbdev dynamic_link_descriptor const & desc = descriptors[k]; 13351c0b2f7Stbbdev pointer_to_handler addr = (pointer_to_handler)dlsym( module, desc.name ); 13451c0b2f7Stbbdev if ( !addr ) { 13551c0b2f7Stbbdev return false; 13651c0b2f7Stbbdev } 13751c0b2f7Stbbdev h[k] = addr; 13851c0b2f7Stbbdev } 13951c0b2f7Stbbdev 14051c0b2f7Stbbdev // Commit the entry points. 14151c0b2f7Stbbdev // Cannot use memset here, because the writes must be atomic. 14251c0b2f7Stbbdev for( std::size_t k = 0; k < required; ++k ) 14351c0b2f7Stbbdev *descriptors[k].handler = h[k]; 14451c0b2f7Stbbdev return true; 14551c0b2f7Stbbdev } 14651c0b2f7Stbbdev 14751c0b2f7Stbbdev #if __TBB_WIN8UI_SUPPORT dynamic_link(const char * library,const dynamic_link_descriptor descriptors[],std::size_t required,dynamic_link_handle *,int flags)14851c0b2f7Stbbdev bool dynamic_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required, dynamic_link_handle*, int flags ) { 14957f524caSIlya Isaev dynamic_link_handle tmp_handle = nullptr; 15051c0b2f7Stbbdev TCHAR wlibrary[256]; 15151c0b2f7Stbbdev if ( MultiByteToWideChar(CP_UTF8, 0, library, -1, wlibrary, 255) == 0 ) return false; 15251c0b2f7Stbbdev if ( flags & DYNAMIC_LINK_LOAD ) 15351c0b2f7Stbbdev tmp_handle = LoadPackagedLibrary( wlibrary, 0 ); 15457f524caSIlya Isaev if (tmp_handle != nullptr){ 15551c0b2f7Stbbdev return resolve_symbols(tmp_handle, descriptors, required); 15651c0b2f7Stbbdev }else{ 15751c0b2f7Stbbdev return false; 15851c0b2f7Stbbdev } 15951c0b2f7Stbbdev } dynamic_unlink(dynamic_link_handle)16051c0b2f7Stbbdev void dynamic_unlink( dynamic_link_handle ) {} dynamic_unlink_all()16151c0b2f7Stbbdev void dynamic_unlink_all() {} 16251c0b2f7Stbbdev #else 16351c0b2f7Stbbdev #if __TBB_DYNAMIC_LOAD_ENABLED 16451c0b2f7Stbbdev /* 16551c0b2f7Stbbdev There is a security issue on Windows: LoadLibrary() may load and execute malicious code. 16651c0b2f7Stbbdev See http://www.microsoft.com/technet/security/advisory/2269637.mspx for details. 16751c0b2f7Stbbdev To avoid the issue, we have to pass full path (not just library name) to LoadLibrary. This 16851c0b2f7Stbbdev function constructs full path to the specified library (it is assumed the library located 16951c0b2f7Stbbdev side-by-side with the tbb.dll. 17051c0b2f7Stbbdev 17151c0b2f7Stbbdev The function constructs absolute path for given relative path. Important: Base directory is not 17251c0b2f7Stbbdev current one, it is the directory tbb.dll loaded from. 17351c0b2f7Stbbdev 17451c0b2f7Stbbdev Example: 17551c0b2f7Stbbdev Let us assume "tbb.dll" is located in "c:\program files\common\intel\" directory, e.g. 17651c0b2f7Stbbdev absolute path of the library is "c:\program files\common\intel\tbb.dll". Absolute path for 17751c0b2f7Stbbdev "tbbmalloc.dll" would be "c:\program files\common\intel\tbbmalloc.dll". Absolute path for 17851c0b2f7Stbbdev "malloc\tbbmalloc.dll" would be "c:\program files\common\intel\malloc\tbbmalloc.dll". 17951c0b2f7Stbbdev */ 18051c0b2f7Stbbdev 18151c0b2f7Stbbdev // Struct handle_storage is used by dynamic_link routine to store handles of 18251c0b2f7Stbbdev // all loaded or pinned dynamic libraries. When TBB is shut down, it calls 18351c0b2f7Stbbdev // dynamic_unlink_all() that unloads modules referenced by handle_storage. 18451c0b2f7Stbbdev // This struct should not have any constructors since it may be used before 18551c0b2f7Stbbdev // the constructor is called. 18651c0b2f7Stbbdev #define MAX_LOADED_MODULES 8 // The number of maximum possible modules which can be loaded 18751c0b2f7Stbbdev 18851c0b2f7Stbbdev using atomic_incrementer = std::atomic<std::size_t>; 18951c0b2f7Stbbdev 19051c0b2f7Stbbdev static struct handles_t { 19151c0b2f7Stbbdev atomic_incrementer my_size; 19251c0b2f7Stbbdev dynamic_link_handle my_handles[MAX_LOADED_MODULES]; 19351c0b2f7Stbbdev addtbb::detail::r1::handles_t19451c0b2f7Stbbdev void add(const dynamic_link_handle &handle) { 19551c0b2f7Stbbdev const std::size_t ind = my_size++; 19651c0b2f7Stbbdev __TBB_ASSERT_EX( ind < MAX_LOADED_MODULES, "Too many modules are loaded" ); 19751c0b2f7Stbbdev my_handles[ind] = handle; 19851c0b2f7Stbbdev } 19951c0b2f7Stbbdev freetbb::detail::r1::handles_t20051c0b2f7Stbbdev void free() { 20151c0b2f7Stbbdev const std::size_t size = my_size; 20251c0b2f7Stbbdev for (std::size_t i=0; i<size; ++i) 20351c0b2f7Stbbdev dynamic_unlink( my_handles[i] ); 20451c0b2f7Stbbdev } 20551c0b2f7Stbbdev } handles; 20651c0b2f7Stbbdev 20751c0b2f7Stbbdev static std::once_flag init_dl_data_state; 20851c0b2f7Stbbdev 20951c0b2f7Stbbdev static struct ap_data_t { 21051c0b2f7Stbbdev char _path[PATH_MAX+1]; 21151c0b2f7Stbbdev std::size_t _len; 21251c0b2f7Stbbdev } ap_data; 21351c0b2f7Stbbdev init_ap_data()21451c0b2f7Stbbdev static void init_ap_data() { 21551c0b2f7Stbbdev #if _WIN32 21651c0b2f7Stbbdev // Get handle of our DLL first. 21751c0b2f7Stbbdev HMODULE handle; 21851c0b2f7Stbbdev BOOL brc = GetModuleHandleEx( 21951c0b2f7Stbbdev GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 22051c0b2f7Stbbdev (LPCSTR)( & dynamic_link ), // any function inside the library can be used for the address 22151c0b2f7Stbbdev & handle 22251c0b2f7Stbbdev ); 22351c0b2f7Stbbdev if ( !brc ) { // Error occurred. 22451c0b2f7Stbbdev int err = GetLastError(); 22551c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_sys_fail, "GetModuleHandleEx", err ); 22651c0b2f7Stbbdev return; 22751c0b2f7Stbbdev } 22851c0b2f7Stbbdev // Now get path to our DLL. 22951c0b2f7Stbbdev DWORD drc = GetModuleFileName( handle, ap_data._path, static_cast< DWORD >( PATH_MAX ) ); 23051c0b2f7Stbbdev if ( drc == 0 ) { // Error occurred. 23151c0b2f7Stbbdev int err = GetLastError(); 23251c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_sys_fail, "GetModuleFileName", err ); 23351c0b2f7Stbbdev return; 23451c0b2f7Stbbdev } 23551c0b2f7Stbbdev if ( drc >= PATH_MAX ) { // Buffer too short. 23651c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_buff_too_small ); 23751c0b2f7Stbbdev return; 23851c0b2f7Stbbdev } 23951c0b2f7Stbbdev // Find the position of the last backslash. 24051c0b2f7Stbbdev char *backslash = std::strrchr( ap_data._path, '\\' ); 24151c0b2f7Stbbdev 24251c0b2f7Stbbdev if ( !backslash ) { // Backslash not found. 24357f524caSIlya Isaev __TBB_ASSERT_EX( backslash != nullptr, "Unbelievable."); 24451c0b2f7Stbbdev return; 24551c0b2f7Stbbdev } 24651c0b2f7Stbbdev __TBB_ASSERT_EX( backslash >= ap_data._path, "Unbelievable."); 24751c0b2f7Stbbdev ap_data._len = (std::size_t)(backslash - ap_data._path) + 1; 24851c0b2f7Stbbdev *(backslash+1) = 0; 24951c0b2f7Stbbdev #else 25051c0b2f7Stbbdev // Get the library path 25151c0b2f7Stbbdev Dl_info dlinfo; 25251c0b2f7Stbbdev int res = dladdr( (void*)&dynamic_link, &dlinfo ); // any function inside the library can be used for the address 25351c0b2f7Stbbdev if ( !res ) { 25451c0b2f7Stbbdev char const * err = dlerror(); 25551c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_sys_fail, "dladdr", err ); 25651c0b2f7Stbbdev return; 25751c0b2f7Stbbdev } else { 25857f524caSIlya Isaev __TBB_ASSERT_EX( dlinfo.dli_fname!=nullptr, "Unbelievable." ); 25951c0b2f7Stbbdev } 26051c0b2f7Stbbdev 26151c0b2f7Stbbdev char const *slash = std::strrchr( dlinfo.dli_fname, '/' ); 26251c0b2f7Stbbdev std::size_t fname_len=0; 26351c0b2f7Stbbdev if ( slash ) { 26451c0b2f7Stbbdev __TBB_ASSERT_EX( slash >= dlinfo.dli_fname, "Unbelievable."); 26551c0b2f7Stbbdev fname_len = (std::size_t)(slash - dlinfo.dli_fname) + 1; 26651c0b2f7Stbbdev } 26751c0b2f7Stbbdev 26851c0b2f7Stbbdev std::size_t rc; 26951c0b2f7Stbbdev if ( dlinfo.dli_fname[0]=='/' ) { 27051c0b2f7Stbbdev // The library path is absolute 27151c0b2f7Stbbdev rc = 0; 27251c0b2f7Stbbdev ap_data._len = 0; 27351c0b2f7Stbbdev } else { 27451c0b2f7Stbbdev // The library path is relative so get the current working directory 27551c0b2f7Stbbdev if ( !getcwd( ap_data._path, sizeof(ap_data._path)/sizeof(ap_data._path[0]) ) ) { 27651c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_buff_too_small ); 27751c0b2f7Stbbdev return; 27851c0b2f7Stbbdev } 27951c0b2f7Stbbdev ap_data._len = std::strlen( ap_data._path ); 28051c0b2f7Stbbdev ap_data._path[ap_data._len++]='/'; 28151c0b2f7Stbbdev rc = ap_data._len; 28251c0b2f7Stbbdev } 28351c0b2f7Stbbdev 28451c0b2f7Stbbdev if ( fname_len>0 ) { 2854ca7d964SAnton Potapov ap_data._len += fname_len; 28651c0b2f7Stbbdev if ( ap_data._len>PATH_MAX ) { 28751c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_buff_too_small ); 28851c0b2f7Stbbdev ap_data._len=0; 28951c0b2f7Stbbdev return; 29051c0b2f7Stbbdev } 29151c0b2f7Stbbdev std::strncpy( ap_data._path+rc, dlinfo.dli_fname, fname_len ); 29251c0b2f7Stbbdev ap_data._path[ap_data._len]=0; 29351c0b2f7Stbbdev } 29451c0b2f7Stbbdev #endif /* _WIN32 */ 29551c0b2f7Stbbdev } 29651c0b2f7Stbbdev init_dl_data()29751c0b2f7Stbbdev static void init_dl_data() { 29851c0b2f7Stbbdev init_ap_data(); 29951c0b2f7Stbbdev } 30051c0b2f7Stbbdev 30151c0b2f7Stbbdev /* 30251c0b2f7Stbbdev The function constructs absolute path for given relative path. Important: Base directory is not 30351c0b2f7Stbbdev current one, it is the directory libtbb.so loaded from. 30451c0b2f7Stbbdev 30551c0b2f7Stbbdev Arguments: 30651c0b2f7Stbbdev in name -- Name of a file (may be with relative path; it must not be an absolute one). 30751c0b2f7Stbbdev out path -- Buffer to save result (absolute path) to. 30851c0b2f7Stbbdev in len -- Size of buffer. 30951c0b2f7Stbbdev ret -- 0 -- Error occurred. 31051c0b2f7Stbbdev > len -- Buffer too short, required size returned. 31151c0b2f7Stbbdev otherwise -- Ok, number of characters (incl. terminating null) written to buffer. 31251c0b2f7Stbbdev */ abs_path(char const * name,char * path,std::size_t len)31351c0b2f7Stbbdev static std::size_t abs_path( char const * name, char * path, std::size_t len ) { 31451c0b2f7Stbbdev if ( ap_data._len == 0 ) 31551c0b2f7Stbbdev return 0; 31651c0b2f7Stbbdev 31751c0b2f7Stbbdev std::size_t name_len = std::strlen( name ); 31851c0b2f7Stbbdev std::size_t full_len = name_len+ap_data._len; 31951c0b2f7Stbbdev if ( full_len < len ) { 32057f524caSIlya Isaev __TBB_ASSERT( ap_data._path[ap_data._len] == 0, nullptr); 32157f524caSIlya Isaev __TBB_ASSERT( std::strlen(ap_data._path) == ap_data._len, nullptr); 32251c0b2f7Stbbdev std::strncpy( path, ap_data._path, ap_data._len + 1 ); 32357f524caSIlya Isaev __TBB_ASSERT( path[ap_data._len] == 0, nullptr); 32451c0b2f7Stbbdev std::strncat( path, name, len - ap_data._len ); 32557f524caSIlya Isaev __TBB_ASSERT( std::strlen(path) == full_len, nullptr); 32651c0b2f7Stbbdev } 32751c0b2f7Stbbdev return full_len+1; // +1 for null character 32851c0b2f7Stbbdev } 32951c0b2f7Stbbdev #endif // __TBB_DYNAMIC_LOAD_ENABLED init_dynamic_link_data()33051c0b2f7Stbbdev void init_dynamic_link_data() { 33151c0b2f7Stbbdev #if __TBB_DYNAMIC_LOAD_ENABLED 33251c0b2f7Stbbdev std::call_once( init_dl_data_state, init_dl_data ); 33351c0b2f7Stbbdev #endif 33451c0b2f7Stbbdev } 33551c0b2f7Stbbdev 33651c0b2f7Stbbdev #if __USE_STATIC_DL_INIT 33751c0b2f7Stbbdev // ap_data structure is initialized with current directory on Linux. 33851c0b2f7Stbbdev // So it should be initialized as soon as possible since the current directory may be changed. 33951c0b2f7Stbbdev // static_init_ap_data object provides this initialization during library loading. 34051c0b2f7Stbbdev static struct static_init_dl_data_t { static_init_dl_data_ttbb::detail::r1::static_init_dl_data_t34151c0b2f7Stbbdev static_init_dl_data_t() { 34251c0b2f7Stbbdev init_dynamic_link_data(); 34351c0b2f7Stbbdev } 34451c0b2f7Stbbdev } static_init_dl_data; 34551c0b2f7Stbbdev #endif 34651c0b2f7Stbbdev 34751c0b2f7Stbbdev #if __TBB_WEAK_SYMBOLS_PRESENT weak_symbol_link(const dynamic_link_descriptor descriptors[],std::size_t required)34851c0b2f7Stbbdev static bool weak_symbol_link( const dynamic_link_descriptor descriptors[], std::size_t required ) 34951c0b2f7Stbbdev { 35051c0b2f7Stbbdev // Check if the required entries are present in what was loaded into our process. 35151c0b2f7Stbbdev for ( std::size_t k = 0; k < required; ++k ) 35251c0b2f7Stbbdev if ( !descriptors[k].ptr ) 35351c0b2f7Stbbdev return false; 35451c0b2f7Stbbdev // Commit the entry points. 35551c0b2f7Stbbdev for ( std::size_t k = 0; k < required; ++k ) 35651c0b2f7Stbbdev *descriptors[k].handler = (pointer_to_handler) descriptors[k].ptr; 35751c0b2f7Stbbdev return true; 35851c0b2f7Stbbdev } 35951c0b2f7Stbbdev #else weak_symbol_link(const dynamic_link_descriptor[],std::size_t)36051c0b2f7Stbbdev static bool weak_symbol_link( const dynamic_link_descriptor[], std::size_t ) { 36151c0b2f7Stbbdev return false; 36251c0b2f7Stbbdev } 36351c0b2f7Stbbdev #endif /* __TBB_WEAK_SYMBOLS_PRESENT */ 36451c0b2f7Stbbdev dynamic_unlink(dynamic_link_handle handle)36551c0b2f7Stbbdev void dynamic_unlink( dynamic_link_handle handle ) { 36651c0b2f7Stbbdev #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */ 36751c0b2f7Stbbdev if ( !dlclose ) return; 36851c0b2f7Stbbdev #endif 36951c0b2f7Stbbdev if ( handle ) { 37051c0b2f7Stbbdev dlclose( handle ); 37151c0b2f7Stbbdev } 37251c0b2f7Stbbdev } 37351c0b2f7Stbbdev dynamic_unlink_all()37451c0b2f7Stbbdev void dynamic_unlink_all() { 37551c0b2f7Stbbdev #if __TBB_DYNAMIC_LOAD_ENABLED 37651c0b2f7Stbbdev handles.free(); 37751c0b2f7Stbbdev #endif 37851c0b2f7Stbbdev } 37951c0b2f7Stbbdev global_symbols_link(const char * library,const dynamic_link_descriptor descriptors[],std::size_t required)38051c0b2f7Stbbdev static dynamic_link_handle global_symbols_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required ) { 38151c0b2f7Stbbdev dynamic_link_handle library_handle{}; 38251c0b2f7Stbbdev #if _WIN32 383478de5b1Stbbdev auto res = GetModuleHandleEx(0, library, &library_handle); 3848827ea7dSLong Nguyen __TBB_ASSERT_EX((res && library_handle) || (!res && !library_handle), nullptr); 38551c0b2f7Stbbdev #else /* _WIN32 */ 38651c0b2f7Stbbdev #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */ 38751c0b2f7Stbbdev if ( !dlopen ) return 0; 38851c0b2f7Stbbdev #endif /* !__TBB_DYNAMIC_LOAD_ENABLED */ 38951c0b2f7Stbbdev // RTLD_GLOBAL - to guarantee that old TBB will find the loaded library 39051c0b2f7Stbbdev // RTLD_NOLOAD - not to load the library without the full path 39151c0b2f7Stbbdev library_handle = dlopen(library, RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); 39251c0b2f7Stbbdev #endif /* _WIN32 */ 39351c0b2f7Stbbdev if (library_handle) { 39451c0b2f7Stbbdev if (!resolve_symbols(library_handle, descriptors, required)) { 39551c0b2f7Stbbdev dynamic_unlink(library_handle); 39651c0b2f7Stbbdev library_handle = nullptr; 39751c0b2f7Stbbdev } 39851c0b2f7Stbbdev } 39951c0b2f7Stbbdev return library_handle; 40051c0b2f7Stbbdev } 40151c0b2f7Stbbdev save_library_handle(dynamic_link_handle src,dynamic_link_handle * dst)40251c0b2f7Stbbdev static void save_library_handle( dynamic_link_handle src, dynamic_link_handle *dst ) { 40351c0b2f7Stbbdev __TBB_ASSERT_EX( src, "The library handle to store must be non-zero" ); 40451c0b2f7Stbbdev if ( dst ) 40551c0b2f7Stbbdev *dst = src; 40651c0b2f7Stbbdev #if __TBB_DYNAMIC_LOAD_ENABLED 40751c0b2f7Stbbdev else 40851c0b2f7Stbbdev handles.add( src ); 40951c0b2f7Stbbdev #endif /* __TBB_DYNAMIC_LOAD_ENABLED */ 41051c0b2f7Stbbdev } 41151c0b2f7Stbbdev 4120354fc10SIvan Kochin #if !_WIN32 loading_flags(bool local_binding)4130354fc10SIvan Kochin int loading_flags(bool local_binding) { 4140354fc10SIvan Kochin int flags = RTLD_NOW; 4150354fc10SIvan Kochin if (local_binding) { 4160354fc10SIvan Kochin flags = flags | RTLD_LOCAL; 417883c2e52SKhem Raj #if (__linux__ && __GLIBC__) && !__TBB_USE_SANITIZERS 418*4bb2faa0Ssarathnandu if( !GetBoolEnvironmentVariable("TBB_ENABLE_SANITIZERS") ) { 4190354fc10SIvan Kochin flags = flags | RTLD_DEEPBIND; 420*4bb2faa0Ssarathnandu } 421a080baf9SAlex #endif 4220354fc10SIvan Kochin } else { 4230354fc10SIvan Kochin flags = flags | RTLD_GLOBAL; 4240354fc10SIvan Kochin } 4250354fc10SIvan Kochin return flags; 4260354fc10SIvan Kochin } 427112076d0SIlya Isaev #endif 42851c0b2f7Stbbdev dynamic_load(const char * library,const dynamic_link_descriptor descriptors[],std::size_t required,bool local_binding)4290354fc10SIvan Kochin dynamic_link_handle dynamic_load( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required, bool local_binding ) { 4300354fc10SIvan Kochin ::tbb::detail::suppress_unused_warning( library, descriptors, required, local_binding ); 4310354fc10SIvan Kochin #if __TBB_DYNAMIC_LOAD_ENABLED 43251c0b2f7Stbbdev std::size_t const len = PATH_MAX + 1; 43351c0b2f7Stbbdev char path[ len ]; 43451c0b2f7Stbbdev std::size_t rc = abs_path( library, path, len ); 43551c0b2f7Stbbdev if ( 0 < rc && rc <= len ) { 43651c0b2f7Stbbdev #if _WIN32 43751c0b2f7Stbbdev // Prevent Windows from displaying silly message boxes if it fails to load library 43851c0b2f7Stbbdev // (e.g. because of MS runtime problems - one of those crazy manifest related ones) 43951c0b2f7Stbbdev UINT prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS); 44051c0b2f7Stbbdev #endif /* _WIN32 */ 441112076d0SIlya Isaev // The second argument (loading_flags) is ignored on Windows 4420354fc10SIvan Kochin dynamic_link_handle library_handle = dlopen( path, loading_flags(local_binding) ); 44351c0b2f7Stbbdev #if _WIN32 44451c0b2f7Stbbdev SetErrorMode (prev_mode); 44551c0b2f7Stbbdev #endif /* _WIN32 */ 44651c0b2f7Stbbdev if( library_handle ) { 44751c0b2f7Stbbdev if( !resolve_symbols( library_handle, descriptors, required ) ) { 44851c0b2f7Stbbdev // The loaded library does not contain all the expected entry points 44951c0b2f7Stbbdev dynamic_unlink( library_handle ); 45057f524caSIlya Isaev library_handle = nullptr; 45151c0b2f7Stbbdev } 45251c0b2f7Stbbdev } else 45351c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_lib_not_found, path, dlerror() ); 45451c0b2f7Stbbdev return library_handle; 45551c0b2f7Stbbdev } else if ( rc>len ) 45651c0b2f7Stbbdev DYNAMIC_LINK_WARNING( dl_buff_too_small ); 45751c0b2f7Stbbdev // rc == 0 means failing of init_ap_data so the warning has already been issued. 45851c0b2f7Stbbdev 45951c0b2f7Stbbdev #endif /* __TBB_DYNAMIC_LOAD_ENABLED */ 46057f524caSIlya Isaev return nullptr; 46151c0b2f7Stbbdev } 46251c0b2f7Stbbdev dynamic_link(const char * library,const dynamic_link_descriptor descriptors[],std::size_t required,dynamic_link_handle * handle,int flags)46351c0b2f7Stbbdev bool dynamic_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required, dynamic_link_handle *handle, int flags ) { 46451c0b2f7Stbbdev init_dynamic_link_data(); 46551c0b2f7Stbbdev 46651c0b2f7Stbbdev // TODO: May global_symbols_link find weak symbols? 46757f524caSIlya Isaev dynamic_link_handle library_handle = ( flags & DYNAMIC_LINK_GLOBAL ) ? global_symbols_link( library, descriptors, required ) : nullptr; 46851c0b2f7Stbbdev 4690354fc10SIvan Kochin #if defined(_MSC_VER) && _MSC_VER <= 1900 4700354fc10SIvan Kochin #pragma warning (push) 4710354fc10SIvan Kochin // MSVC 2015 warning: 'int': forcing value to bool 'true' or 'false' 4720354fc10SIvan Kochin #pragma warning (disable: 4800) 4730354fc10SIvan Kochin #endif 47451c0b2f7Stbbdev if ( !library_handle && ( flags & DYNAMIC_LINK_LOAD ) ) 4753e4ab550SIvan Kochin library_handle = dynamic_load( library, descriptors, required, flags & DYNAMIC_LINK_LOCAL ); 47651c0b2f7Stbbdev 4770354fc10SIvan Kochin #if defined(_MSC_VER) && _MSC_VER <= 1900 4780354fc10SIvan Kochin #pragma warning (pop) 4790354fc10SIvan Kochin #endif 48051c0b2f7Stbbdev if ( !library_handle && ( flags & DYNAMIC_LINK_WEAK ) ) 48151c0b2f7Stbbdev return weak_symbol_link( descriptors, required ); 48251c0b2f7Stbbdev 48351c0b2f7Stbbdev if ( library_handle ) { 48451c0b2f7Stbbdev save_library_handle( library_handle, handle ); 48551c0b2f7Stbbdev return true; 48651c0b2f7Stbbdev } 48751c0b2f7Stbbdev return false; 48851c0b2f7Stbbdev } 48951c0b2f7Stbbdev 49051c0b2f7Stbbdev #endif /*__TBB_WIN8UI_SUPPORT*/ 49151c0b2f7Stbbdev #else /* __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED */ 49251c0b2f7Stbbdev bool dynamic_link( const char*, const dynamic_link_descriptor*, std::size_t, dynamic_link_handle *handle, int ) { 49351c0b2f7Stbbdev if ( handle ) 49451c0b2f7Stbbdev *handle=0; 49551c0b2f7Stbbdev return false; 49651c0b2f7Stbbdev } 49751c0b2f7Stbbdev void dynamic_unlink( dynamic_link_handle ) {} 49851c0b2f7Stbbdev void dynamic_unlink_all() {} 49951c0b2f7Stbbdev #endif /* __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED */ 50051c0b2f7Stbbdev 50151c0b2f7Stbbdev } // namespace r1 50251c0b2f7Stbbdev } // namespace detail 50351c0b2f7Stbbdev } // namespace tbb 504