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