1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of module related functions in the Win32 API
21 #include "pal/dbgmsg.h"
22 SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do this first
24 #include "pal/thread.hpp"
25 #include "pal/malloc.hpp"
26 #include "pal/file.hpp"
27 #include "pal/palinternal.h"
28 #include "pal/module.h"
30 #include "pal/process.h"
32 #include "pal/utils.h"
34 #include "pal/modulename.h"
35 #include "pal/environ.h"
36 #include "pal/virtual.h"
37 #include "pal/map.hpp"
38 #include "pal/stackstring.hpp"
40 #include <sys/param.h>
46 #else // NEED_DLCOMPAT
48 #endif // NEED_DLCOMPAT
52 #include <mach-o/dyld.h>
53 #include <mach-o/loader.h>
56 #include <sys/types.h>
59 #if HAVE_GNU_LIBNAMES_H
60 #include <gnu/lib-names.h>
63 using namespace CorUnix;
65 // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
66 // defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
67 // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(LOADER)
70 /* macro definitions **********************************************************/
72 /* get the full name of a module if available, and the short name otherwise*/
73 #define MODNAME(x) ((x)->lib_name)
75 /* Which path should FindLibrary search? */
76 #if defined(__APPLE__)
77 #define LIBSEARCHPATH "DYLD_LIBRARY_PATH"
79 #define LIBSEARCHPATH "LD_LIBRARY_PATH"
82 #define LIBC_NAME_WITHOUT_EXTENSION "libc"
84 /* static variables ***********************************************************/
86 /* critical section that regulates access to the module list */
87 CRITICAL_SECTION module_critsec;
89 /* always the first, in the in-load-order list */
91 MODSTRUCT *pal_module = nullptr;
93 char * g_szCoreCLRPath = nullptr;
95 int MaxWCharToAcpLength = 3;
97 /* static function declarations ***********************************************/
99 template<class TChar> static bool LOADVerifyLibraryPath(const TChar *libraryPath);
100 static bool LOADConvertLibraryPathWideStringToMultibyteString(
101 LPCWSTR wideLibraryPath,
102 LPSTR multibyteLibraryPath,
103 INT *multibyteLibraryPathLengthRef);
104 static BOOL LOADValidateModule(MODSTRUCT *module);
105 static LPWSTR LOADGetModuleFileName(MODSTRUCT *module);
106 static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath);
107 static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath);
108 static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain);
109 static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic);
110 static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic);
111 static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved);
113 /* API function definitions ***************************************************/
124 IN LPCSTR lpLibFileName)
126 return LoadLibraryExA(lpLibFileName, nullptr, 0);
138 IN LPCWSTR lpLibFileName)
140 return LoadLibraryExW(lpLibFileName, nullptr, 0);
152 IN LPCSTR lpLibFileName,
153 IN /*Reserved*/ HANDLE hFile,
158 // UNIXTODO: Implement this!
159 ASSERT("Needs Implementation!!!");
163 LPSTR lpstr = nullptr;
164 HMODULE hModule = nullptr;
166 PERF_ENTRY(LoadLibraryA);
167 ENTRY("LoadLibraryExA (lpLibFileName=%p (%s)) \n",
168 (lpLibFileName) ? lpLibFileName : "NULL",
169 (lpLibFileName) ? lpLibFileName : "NULL");
171 if (!LOADVerifyLibraryPath(lpLibFileName))
176 /* do the Dos/Unix conversion on our own copy of the name */
177 lpstr = strdup(lpLibFileName);
180 ERROR("strdup failure!\n");
181 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
184 FILEDosToUnixPathA(lpstr);
186 hModule = LOADLoadLibrary(lpstr, TRUE);
188 /* let LOADLoadLibrary call SetLastError */
190 if (lpstr != nullptr)
195 LOGEXIT("LoadLibraryExA returns HMODULE %p\n", hModule);
196 PERF_EXIT(LoadLibraryExA);
210 IN LPCWSTR lpLibFileName,
211 IN /*Reserved*/ HANDLE hFile,
216 // UNIXTODO: Implement this!
217 ASSERT("Needs Implementation!!!");
223 PathCharString pathstr;
224 HMODULE hModule = nullptr;
226 PERF_ENTRY(LoadLibraryExW);
227 ENTRY("LoadLibraryExW (lpLibFileName=%p (%S)) \n",
228 lpLibFileName ? lpLibFileName : W16_NULLSTRING,
229 lpLibFileName ? lpLibFileName : W16_NULLSTRING);
231 if (!LOADVerifyLibraryPath(lpLibFileName))
236 lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
237 if (nullptr == lpstr)
241 if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
246 /* do the Dos/Unix conversion on our own copy of the name */
247 FILEDosToUnixPathA(lpstr);
248 pathstr.CloseBuffer(name_length);
250 /* let LOADLoadLibrary call SetLastError in case of failure */
251 hModule = LOADLoadLibrary(lpstr, TRUE);
254 LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
255 PERF_EXIT(LoadLibraryExW);
269 IN LPCSTR lpProcName)
272 FARPROC ProcAddress = nullptr;
273 LPCSTR symbolName = lpProcName;
275 PERF_ENTRY(GetProcAddress);
276 ENTRY("GetProcAddress (hModule=%p, lpProcName=%p (%s))\n",
277 hModule, lpProcName ? lpProcName : "NULL", lpProcName ? lpProcName : "NULL");
281 module = (MODSTRUCT *) hModule;
283 /* try to assert on attempt to locate symbol by ordinal */
284 /* this can't be an exact test for HIWORD((DWORD)lpProcName) == 0
285 because of the address range reserved for ordinals contain can
286 be a valid string address on non-Windows systems
288 if ((DWORD_PTR)lpProcName < GetVirtualPageSize())
290 ASSERT("Attempt to locate symbol by ordinal?!\n");
293 /* parameter validation */
295 if ((lpProcName == nullptr) || (*lpProcName == '\0'))
297 TRACE("No function name given\n");
298 SetLastError(ERROR_INVALID_PARAMETER);
302 if (!LOADValidateModule(module))
304 TRACE("Invalid module handle %p\n", hModule);
305 SetLastError(ERROR_INVALID_HANDLE);
309 // Get the symbol's address.
311 // If we're looking for a symbol inside the PAL, we try the PAL_ variant
312 // first because otherwise we run the risk of having the non-PAL_
313 // variant preferred over the PAL's implementation.
314 if (pal_module && module->dl_handle == pal_module->dl_handle)
316 int iLen = 4 + strlen(lpProcName) + 1;
317 LPSTR lpPALProcName = (LPSTR) alloca(iLen);
319 if (strcpy_s(lpPALProcName, iLen, "PAL_") != SAFECRT_SUCCESS)
321 ERROR("strcpy_s failed!\n");
322 SetLastError(ERROR_INSUFFICIENT_BUFFER);
326 if (strcat_s(lpPALProcName, iLen, lpProcName) != SAFECRT_SUCCESS)
328 ERROR("strcat_s failed!\n");
329 SetLastError(ERROR_INSUFFICIENT_BUFFER);
333 ProcAddress = (FARPROC) dlsym(module->dl_handle, lpPALProcName);
334 symbolName = lpPALProcName;
337 // If we aren't looking inside the PAL or we didn't find a PAL_ variant
338 // inside the PAL, fall back to a normal search.
339 if (ProcAddress == nullptr)
341 ProcAddress = (FARPROC) dlsym(module->dl_handle, lpProcName);
346 TRACE("Symbol %s found at address %p in module %p (named %S)\n",
347 lpProcName, ProcAddress, module, MODNAME(module));
349 /* if we don't know the module's full name yet, this is our chance to obtain it */
350 if (!module->lib_name && module->dl_handle)
352 const char* libName = PAL_dladdr((LPVOID)ProcAddress);
355 module->lib_name = UTIL_MBToWC_Alloc(libName, -1);
356 if (nullptr == module->lib_name)
358 ERROR("MBToWC failure; can't save module's full name\n");
362 TRACE("Saving full path of module %p as %s\n",
370 TRACE("Symbol %s not found in module %p (named %S)\n",
371 lpProcName, module, MODNAME(module));
372 SetLastError(ERROR_PROC_NOT_FOUND);
376 LOGEXIT("GetProcAddress returns FARPROC %p\n", ProcAddress);
377 PERF_EXIT(GetProcAddress);
390 IN OUT HMODULE hLibModule)
394 PERF_ENTRY(FreeLibrary);
395 ENTRY("FreeLibrary (hLibModule=%p)\n", hLibModule);
397 retval = LOADFreeLibrary((MODSTRUCT *)hLibModule, TRUE /* fCallDllMain */);
399 LOGEXIT("FreeLibrary returns BOOL %d\n", retval);
400 PERF_EXIT(FreeLibrary);
406 FreeLibraryAndExitThread
414 FreeLibraryAndExitThread(
415 IN HMODULE hLibModule,
418 PERF_ENTRY(FreeLibraryAndExitThread);
419 ENTRY("FreeLibraryAndExitThread()\n");
420 FreeLibrary(hLibModule);
421 ExitThread(dwExitCode);
422 LOGEXIT("FreeLibraryAndExitThread\n");
423 PERF_EXIT(FreeLibraryAndExitThread);
433 because of limitations in the dlopen() mechanism, this will only return the
434 full path name if a relative or absolute path was given to LoadLibrary, or
435 if the module was used in a GetProcAddress call. otherwise, this will return
436 the short name as given to LoadLibrary. The exception is if hModule is
437 NULL : in this case, the full path of the executable is always returned.
443 OUT LPSTR lpFileName,
448 LPWSTR wide_name = nullptr;
450 PERF_ENTRY(GetModuleFileNameA);
451 ENTRY("GetModuleFileNameA (hModule=%p, lpFileName=%p, nSize=%u)\n",
452 hModule, lpFileName, nSize);
455 if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
457 TRACE("Can't find name for invalid module handle %p\n", hModule);
458 SetLastError(ERROR_INVALID_HANDLE);
461 wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
465 ASSERT("Can't find name for valid module handle %p\n", hModule);
466 SetLastError(ERROR_INTERNAL_ERROR);
470 /* Convert module name to Ascii, place it in the supplied buffer */
472 name_length = WideCharToMultiByte(CP_ACP, 0, wide_name, -1, lpFileName,
473 nSize, nullptr, nullptr);
474 if (name_length == 0)
476 TRACE("Buffer too small to copy module's file name.\n");
477 SetLastError(ERROR_INSUFFICIENT_BUFFER);
481 TRACE("File name of module %p is %s\n", hModule, lpFileName);
482 retval = name_length;
485 LOGEXIT("GetModuleFileNameA returns DWORD %d\n", retval);
486 PERF_EXIT(GetModuleFileNameA);
497 because of limitations in the dlopen() mechanism, this will only return the
498 full path name if a relative or absolute path was given to LoadLibrary, or
499 if the module was used in a GetProcAddress call. otherwise, this will return
500 the short name as given to LoadLibrary. The exception is if hModule is
501 NULL : in this case, the full path of the executable is always returned.
507 OUT LPWSTR lpFileName,
512 LPWSTR wide_name = nullptr;
514 PERF_ENTRY(GetModuleFileNameW);
515 ENTRY("GetModuleFileNameW (hModule=%p, lpFileName=%p, nSize=%u)\n",
516 hModule, lpFileName, nSize);
520 wcscpy_s(lpFileName, nSize, W(""));
522 if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
524 TRACE("Can't find name for invalid module handle %p\n", hModule);
525 SetLastError(ERROR_INVALID_HANDLE);
528 wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
532 TRACE("Can't find name for valid module handle %p\n", hModule);
533 SetLastError(ERROR_INTERNAL_ERROR);
537 /* Copy module name into supplied buffer */
539 name_length = PAL_wcslen(wide_name);
540 if (name_length >= (INT)nSize)
542 TRACE("Buffer too small (%u) to copy module's file name (%u).\n", nSize, name_length);
544 SetLastError(ERROR_INSUFFICIENT_BUFFER);
548 wcscpy_s(lpFileName, nSize, wide_name);
550 TRACE("file name of module %p is %S\n", hModule, lpFileName);
551 retval = (DWORD)name_length;
554 LOGEXIT("GetModuleFileNameW returns DWORD %u\n", retval);
555 PERF_EXIT(GetModuleFileNameW);
559 LPCSTR FixLibCName(LPCSTR shortAsciiName)
561 // Check whether we have been requested to load 'libc'. If that's the case, then:
562 // * For Linux, use the full name of the library that is defined in <gnu/lib-names.h> by the
563 // LIBC_SO constant. The problem is that calling dlopen("libc.so") will fail for libc even
564 // though it works for other libraries. The reason is that libc.so is just linker script
565 // (i.e. a test file).
566 // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
567 // * For macOS, use constant value absolute path "/usr/lib/libc.dylib".
568 // * For FreeBSD, use constant value "libc.so.7".
569 // * For rest of Unices, use constant value "libc.so".
570 if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
572 #if defined(__APPLE__)
573 return "/usr/lib/libc.dylib";
574 #elif defined(__FreeBSD__)
576 #elif defined(LIBC_SO)
583 return shortAsciiName;
588 PAL_LoadLibraryDirect
590 Loads a library using a system call, without registering the library with the module list.
592 Returns the system handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
594 NATIVE_LIBRARY_HANDLE
596 PAL_LoadLibraryDirect(
597 IN LPCWSTR lpLibFileName)
599 PathCharString pathstr;
600 CHAR * lpstr = nullptr;
601 LPCSTR lpcstr = nullptr;
603 NATIVE_LIBRARY_HANDLE dl_handle = nullptr;
605 PERF_ENTRY(LoadLibraryDirect);
606 ENTRY("LoadLibraryDirect (lpLibFileName=%p (%S)) \n",
607 lpLibFileName ? lpLibFileName : W16_NULLSTRING,
608 lpLibFileName ? lpLibFileName : W16_NULLSTRING);
610 if (!LOADVerifyLibraryPath(lpLibFileName))
615 lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
616 if (nullptr == lpstr)
620 if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
625 /* do the Dos/Unix conversion on our own copy of the name */
626 FILEDosToUnixPathA(lpstr);
627 pathstr.CloseBuffer(name_length);
628 lpcstr = FixLibCName(lpstr);
630 dl_handle = LOADLoadLibraryDirect(lpcstr);
633 LOGEXIT("LoadLibraryDirect returns NATIVE_LIBRARY_HANDLE %p\n", dl_handle);
634 PERF_EXIT(LoadLibraryDirect);
640 PAL_FreeLibraryDirect
642 Free a loaded library
644 Returns true on success, false on failure.
648 PAL_FreeLibraryDirect(
649 IN NATIVE_LIBRARY_HANDLE dl_handle)
652 PERF_ENTRY(PAL_FreeLibraryDirect);
653 ENTRY("PAL_FreeLibraryDirect (dl_handle=%p) \n", dl_handle);
655 retValue = dlclose(dl_handle) == 0;
657 LOGEXIT("PAL_FreeLibraryDirect returns BOOL %p\n", retValue);
658 PERF_EXIT(PAL_FreeLibraryDirect);
664 PAL_GetProcAddressDirect
666 Get the address corresponding to a symbol in a loaded native library.
668 Returns the address of the sumbol loaded in memory.
672 PAL_GetProcAddressDirect(
673 IN NATIVE_LIBRARY_HANDLE dl_handle,
674 IN LPCSTR lpProcName)
677 FARPROC address = nullptr;
679 PERF_ENTRY(PAL_GetProcAddressDirect);
680 ENTRY("PAL_GetProcAddressDirect (lpLibFileName=%p (%S)) \n",
681 lpProcName ? lpProcName : "NULL",
682 lpProcName ? lpProcName : "NULL");
684 address = (FARPROC) dlsym(dl_handle, lpProcName);
686 LOGEXIT("PAL_GetProcAddressDirect returns FARPROC %p\n", address);
687 PERF_EXIT(PAL_GetProcAddressDirect);
695 Register the module with the target module and return a module handle in
696 the target module's context. Doesn't call the DllMain because it is used
697 as part of calling DllMain in the calling module.
703 IN LPCSTR lpLibFileName)
705 HINSTANCE hinstance = nullptr;
707 int err = PAL_InitializeDLL();
710 PERF_ENTRY(PAL_RegisterModule);
711 ENTRY("PAL_RegisterModule(%s)\n", lpLibFileName ? lpLibFileName : "");
715 NATIVE_LIBRARY_HANDLE dl_handle = LOADLoadLibraryDirect(lpLibFileName);
718 // This only creates/adds the module handle and doesn't call DllMain
719 hinstance = LOADAddModule(dl_handle, lpLibFileName);
724 LOGEXIT("PAL_RegisterModule returns HINSTANCE %p\n", hinstance);
725 PERF_EXIT(PAL_RegisterModule);
735 Used to cleanup the module HINSTANCE from PAL_RegisterModule.
739 PAL_UnregisterModule(
740 IN HINSTANCE hInstance)
742 PERF_ENTRY(PAL_UnregisterModule);
743 ENTRY("PAL_UnregisterModule(hInstance=%p)\n", hInstance);
745 LOADFreeLibrary((MODSTRUCT *)hInstance, FALSE /* fCallDllMain */);
747 LOGEXIT("PAL_UnregisterModule returns\n");
748 PERF_EXIT(PAL_UnregisterModule);
754 Map a PE format file into memory like Windows LoadLibrary() would do.
755 Doesn't apply base relocations if the function is relocated.
758 IN hFile - file to map
761 non-NULL - the base address of the mapped image
762 NULL - error, with last error set.
766 PAL_LOADLoadPEFile(HANDLE hFile)
768 ENTRY("PAL_LOADLoadPEFile (hFile=%p)\n", hFile);
770 void * loadedBase = MAPMapPEFile(hFile);
773 if (loadedBase != nullptr)
775 char* envVar = EnvironGetenv("PAL_ForcePEMapFailure");
778 if (strlen(envVar) > 0)
780 TRACE("Forcing failure of PE file map, and retry\n");
781 PAL_LOADUnloadPEFile(loadedBase); // unload it
782 loadedBase = MAPMapPEFile(hFile); // load it again
790 LOGEXIT("PAL_LOADLoadPEFile returns %p\n", loadedBase);
797 Unload a PE file that was loaded by PAL_LOADLoadPEFile().
800 IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
804 FALSE - failure (incorrect ptr, etc.)
808 PAL_LOADUnloadPEFile(PVOID ptr)
812 ENTRY("PAL_LOADUnloadPEFile (ptr=%p)\n", ptr);
816 ERROR( "Invalid pointer value\n" );
820 retval = MAPUnmapPEFile(ptr);
823 LOGEXIT("PAL_LOADUnloadPEFile returns %d\n", retval);
828 PAL_GetSymbolModuleBase
830 Get base address of the module containing a given symbol
833 void *symbol - address of symbol
840 PAL_GetSymbolModuleBase(PVOID symbol)
842 LPCVOID retval = nullptr;
844 PERF_ENTRY(PAL_GetPalModuleBase);
845 ENTRY("PAL_GetPalModuleBase\n");
847 if (symbol == nullptr)
849 TRACE("Can't get base address. Argument symbol == nullptr\n");
850 SetLastError(ERROR_INVALID_DATA);
855 if (dladdr(symbol, &info) != 0)
857 retval = info.dli_fbase;
861 TRACE("Can't get base address of the current module\n");
862 SetLastError(ERROR_INVALID_DATA);
866 LOGEXIT("PAL_GetPalModuleBase returns %p\n", retval);
867 PERF_EXIT(PAL_GetPalModuleBase);
872 PAL_GetLoadLibraryError
874 Wrapper for dlerror() to be used by PAL functions
878 A LPCSTR containing the output of dlerror()
884 PAL_GetLoadLibraryError()
887 PERF_ENTRY(PAL_GetLoadLibraryError);
888 ENTRY("PAL_GetLoadLibraryError");
890 LPCSTR last_error = dlerror();
892 LOGEXIT("PAL_GetLoadLibraryError returns %p\n", last_error);
893 PERF_EXIT(PAL_GetLoadLibraryError);
898 /* Internal PAL functions *****************************************************/
902 LOADInitializeModules
904 Initialize the process-wide list of modules
910 TRUE if initialization succeedded
915 BOOL LOADInitializeModules()
917 _ASSERTE(exe_module.prev == nullptr);
919 InternalInitializeCriticalSection(&module_critsec);
921 // Initialize module for main executable
922 TRACE("Initializing module for main executable\n");
924 exe_module.self = (HMODULE)&exe_module;
925 exe_module.dl_handle = dlopen(nullptr, RTLD_LAZY);
926 if (exe_module.dl_handle == nullptr)
928 ERROR("Executable module will be broken : dlopen(nullptr) failed\n");
931 exe_module.lib_name = nullptr;
932 exe_module.refcount = -1;
933 exe_module.next = &exe_module;
934 exe_module.prev = &exe_module;
935 exe_module.pDllMain = nullptr;
936 exe_module.hinstance = nullptr;
937 exe_module.threadLibCalls = TRUE;
945 Set the exe name path
948 LPWSTR man exe path and name
951 TRUE if initialization succeedded
956 BOOL LOADSetExeName(LPWSTR name)
958 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
959 LPSTR pszExeName = nullptr;
965 // Save the exe path in the exe module struct
966 free(exe_module.lib_name);
967 exe_module.lib_name = name;
969 // For platforms where we can't trust the handle to be constant, we need to
970 // store the inode/device pairs for the modules we just initialized.
971 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
973 struct stat stat_buf;
974 pszExeName = UTIL_WCToMB_Alloc(name, -1);
975 if (nullptr == pszExeName)
977 ERROR("WCToMB failure, unable to get full name of exe\n");
980 if (-1 == stat(pszExeName, &stat_buf))
982 SetLastError(ERROR_MOD_NOT_FOUND);
985 TRACE("Executable has inode %d and device %d\n", stat_buf.st_ino, stat_buf.st_dev);
987 exe_module.inode = stat_buf.st_ino;
988 exe_module.device = stat_buf.st_dev;
993 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1008 Call DllMain for all modules (that have one) with the given "fwReason"
1011 DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1012 DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1014 LPVOID lpReserved : parameter to pass down to DllMain
1015 If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1016 If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1017 and non-NULL if DllMain has been called during process termination.
1022 This is used to send DLL_THREAD_*TACH messages to modules
1025 void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
1027 MODSTRUCT *module = nullptr;
1028 BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */
1029 CPalThread *pThread;
1031 pThread = InternalGetCurrentThread();
1032 if (UserCreatedThread != pThread->GetThreadType())
1037 /* Validate dwReason */
1040 case DLL_PROCESS_ATTACH:
1041 ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n");
1043 case DLL_PROCESS_DETACH:
1044 ASSERT("got called with DLL_PROCESS_DETACH parameter! Why?\n");
1045 InLoadOrder = FALSE;
1047 case DLL_THREAD_ATTACH:
1048 TRACE("Calling DllMain(DLL_THREAD_ATTACH) on all known modules.\n");
1050 case DLL_THREAD_DETACH:
1051 TRACE("Calling DllMain(DLL_THREAD_DETACH) on all known modules.\n");
1052 InLoadOrder = FALSE;
1055 ASSERT("LOADCallDllMain called with unknown parameter %d!\n", dwReason);
1061 module = &exe_module;
1066 module = module->prev;
1068 if (module->threadLibCalls)
1070 if (module->pDllMain)
1072 LOADCallDllMainSafe(module, dwReason, lpReserved);
1077 module = module->next;
1079 } while (module != &exe_module);
1089 MODSTRUCT * module - module to free
1090 BOOL fCallDllMain - if TRUE, call the DllMain function
1096 static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain)
1098 BOOL retval = FALSE;
1104 /* PAL shutdown is in progress - ignore FreeLibrary calls */
1109 if (!LOADValidateModule(module))
1111 TRACE("Can't free invalid module %p\n", module);
1112 SetLastError(ERROR_INVALID_HANDLE);
1116 if (module->refcount == -1)
1118 /* special module - never released */
1124 TRACE("Reference count for module %p (named %S) decreases to %d\n",
1125 module, MODNAME(module), module->refcount);
1127 if (module->refcount != 0)
1133 /* Releasing the last reference : call dlclose(), remove module from the
1134 process-wide module list */
1136 TRACE("Reference count for module %p (named %S) now 0; destroying module structure\n",
1137 module, MODNAME(module));
1139 /* unlink the module structure from the list */
1140 module->prev->next = module->next;
1141 module->next->prev = module->prev;
1143 /* remove the circular reference so that LOADValidateModule will fail */
1144 module->self = nullptr;
1146 /* Call DllMain if the module contains one */
1147 if (fCallDllMain && module->pDllMain)
1149 LOADCallDllMainSafe(module, DLL_PROCESS_DETACH, nullptr);
1152 if (module->hinstance)
1154 PUNREGISTER_MODULE unregisterModule = (PUNREGISTER_MODULE)dlsym(module->dl_handle, "PAL_UnregisterModule");
1155 if (unregisterModule != nullptr)
1157 unregisterModule(module->hinstance);
1159 module->hinstance = nullptr;
1162 if (module->dl_handle && 0 != dlclose(module->dl_handle))
1164 /* report dlclose() failure, but proceed anyway. */
1165 WARN("dlclose() call failed!\n");
1168 /* release all memory */
1169 free(module->lib_name);
1183 Exception-safe call to DllMain.
1186 MODSTRUCT *module : module whose DllMain must be called
1188 DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1189 DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1191 LPVOID lpvReserved : parameter to pass down to DllMain,
1192 If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1193 If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1194 and non-NULL if DllMain has been called during process termination.
1197 BOOL : DllMain's return value
1199 static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved)
1201 #if _ENABLE_DEBUG_MESSAGES_
1202 /* reset ENTRY nesting level back to zero while inside the callback... */
1203 int old_level = DBG_change_entrylevel(0);
1204 #endif /* _ENABLE_DEBUG_MESSAGES_ */
1213 param.module = module;
1214 param.dwReason = dwReason;
1215 param.lpReserved = lpReserved;
1218 PAL_TRY(Param *, pParam, ¶m)
1220 TRACE("Calling DllMain (%p) for module %S\n",
1221 pParam->module->pDllMain,
1222 pParam->module->lib_name ? pParam->module->lib_name : W16_NULLSTRING);
1225 // This module may be foreign to our PAL, so leave our PAL.
1226 // If it depends on us, it will re-enter.
1227 PAL_LeaveHolder holder;
1228 pParam->ret = pParam->module->pDllMain(pParam->module->hinstance, pParam->dwReason, pParam->lpReserved);
1231 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1233 WARN("Call to DllMain (%p) got an unhandled exception; ignoring.\n", module->pDllMain);
1237 #if _ENABLE_DEBUG_MESSAGES_
1238 /* ...and set nesting level back to what it was */
1239 DBG_change_entrylevel(old_level);
1240 #endif /* _ENABLE_DEBUG_MESSAGES_ */
1247 DisableThreadLibraryCalls
1253 DisableThreadLibraryCalls(
1254 IN HMODULE hLibModule)
1258 PERF_ENTRY(DisableThreadLibraryCalls);
1259 ENTRY("DisableThreadLibraryCalls(hLibModule=%p)\n", hLibModule);
1265 /* PAL shutdown in progress - ignore DisableThreadLibraryCalls */
1270 module = (MODSTRUCT *) hLibModule;
1272 if (!LOADValidateModule(module))
1274 // DisableThreadLibraryCalls() does nothing when given
1275 // an invalid module handle. This matches the Windows
1276 // behavior, though it is counter to MSDN.
1277 WARN("Invalid module handle %p\n", hLibModule);
1282 module->threadLibCalls = FALSE;
1287 LOGEXIT("DisableThreadLibraryCalls returns BOOL %d\n", ret);
1288 PERF_EXIT(DisableThreadLibraryCalls);
1292 // Checks the library path for null or empty string. On error, calls SetLastError() and returns false.
1293 template<class TChar>
1294 static bool LOADVerifyLibraryPath(const TChar *libraryPath)
1296 if (libraryPath == nullptr)
1298 ERROR("libraryPath is null\n");
1299 SetLastError(ERROR_MOD_NOT_FOUND);
1302 if (libraryPath[0] == '\0')
1304 ERROR("libraryPath is empty\n");
1305 SetLastError(ERROR_INVALID_PARAMETER);
1311 // Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false.
1312 static bool LOADConvertLibraryPathWideStringToMultibyteString(
1313 LPCWSTR wideLibraryPath,
1314 LPSTR multibyteLibraryPath,
1315 INT *multibyteLibraryPathLengthRef)
1317 _ASSERTE(multibyteLibraryPathLengthRef != nullptr);
1318 _ASSERTE(wideLibraryPath != nullptr);
1320 size_t length = (PAL_wcslen(wideLibraryPath)+1) * MaxWCharToAcpLength;
1321 *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath,
1322 length, nullptr, nullptr);
1324 if (*multibyteLibraryPathLengthRef == 0)
1326 DWORD dwLastError = GetLastError();
1328 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1330 SetLastError(ERROR_INVALID_PARAMETER);
1340 Check whether the given MODSTRUCT pointer is valid
1343 MODSTRUCT *module : module to check
1346 TRUE if module is valid, FALSE otherwise
1349 The module lock MUST be owned.
1352 static BOOL LOADValidateModule(MODSTRUCT *module)
1354 MODSTRUCT *modlist_enum = &exe_module;
1356 /* enumerate through the list of modules to make sure the given handle is
1357 really a module (HMODULEs are actually MODSTRUCT pointers) */
1360 if (module == modlist_enum)
1362 /* found it; check its integrity to be on the safe side */
1363 if (module->self != module)
1365 ERROR("Found corrupt module %p!\n",module);
1368 TRACE("Module %p is valid (name : %S)\n", module, MODNAME(module));
1371 modlist_enum = modlist_enum->next;
1373 while (modlist_enum != &exe_module);
1375 TRACE("Module %p is NOT valid.\n", module);
1381 LOADGetModuleFileName [internal]
1383 Retrieve the module's full path if it is known, the short name given to
1384 LoadLibrary otherwise.
1387 MODSTRUCT *module : module to check
1390 pointer to internal buffer with name of module (Unicode)
1393 this function assumes that the module critical section is held, and that
1394 the module has already been validated.
1396 static LPWSTR LOADGetModuleFileName(MODSTRUCT *module)
1399 /* special case : if module is NULL, we want the name of the executable */
1402 module_name = exe_module.lib_name;
1403 TRACE("Returning name of main executable\n");
1407 /* return "real" name of module if it is known. we have this if LoadLibrary
1408 was given an absolute or relative path; we can also determine it at the
1409 first GetProcAddress call. */
1410 TRACE("Returning full path name of module\n");
1411 return module->lib_name;
1416 LOADLoadLibraryDirect [internal]
1418 Loads a library using a system call, without registering the library with the module list.
1421 LPCSTR libraryNameOrPath: The library to load.
1424 System handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1426 static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath)
1428 _ASSERTE(libraryNameOrPath != nullptr);
1429 _ASSERTE(libraryNameOrPath[0] != '\0');
1431 if (strchr(libraryNameOrPath, '/') != nullptr)
1433 if (access(libraryNameOrPath, F_OK) == -1)
1435 SetLastError(ERROR_MOD_NOT_FOUND);
1436 return (NATIVE_LIBRARY_HANDLE)nullptr;
1440 NATIVE_LIBRARY_HANDLE dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY);
1441 if (dl_handle == nullptr)
1443 SetLastError(ERROR_MOD_NOT_FOUND);
1447 TRACE("dlopen() found module %s\n", libraryNameOrPath);
1457 Allocate and initialize a new MODSTRUCT structure
1460 NATIVE_LIBRARY_HANDLE dl_handle : handle returned by dl_open, goes in MODSTRUCT::dl_handle
1462 char *name : name of new module. after conversion to widechar,
1463 goes in MODSTRUCT::lib_name
1466 a pointer to a new, initialized MODSTRUCT strucutre, or NULL on failure.
1469 'name' is used to initialize MODSTRUCT::lib_name. The other member is set to NULL
1470 In case of failure (in malloc or MBToWC), this function sets LastError.
1472 static MODSTRUCT *LOADAllocModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR name)
1477 /* no match found : try to create a new module structure */
1478 module = (MODSTRUCT *)InternalMalloc(sizeof(MODSTRUCT));
1479 if (nullptr == module)
1481 ERROR("malloc() failed! errno is %d (%s)\n", errno, strerror(errno));
1485 wide_name = UTIL_MBToWC_Alloc(name, -1);
1486 if (nullptr == wide_name)
1488 ERROR("couldn't convert name to a wide-character string\n");
1493 module->dl_handle = dl_handle;
1495 if (isdylib(module))
1497 module->refcount = -1;
1501 module->refcount = 1;
1503 #else // NEED_DLCOMPAT
1504 module->refcount = 1;
1505 #endif // NEED_DLCOMPAT
1506 module->self = module;
1507 module->hinstance = nullptr;
1508 module->threadLibCalls = TRUE;
1509 module->pDllMain = nullptr;
1510 module->next = nullptr;
1511 module->prev = nullptr;
1513 module->lib_name = wide_name;
1520 LOADAddModule [internal]
1522 Registers a system handle to a loaded library with the module list.
1525 NATIVE_LIBRARY_HANDLE dl_handle: System handle to the loaded library.
1526 LPCSTR libraryNameOrPath: The library that was loaded.
1529 PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1531 static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath)
1533 _ASSERTE(dl_handle != nullptr);
1534 _ASSERTE(libraryNameOrPath != nullptr);
1535 _ASSERTE(libraryNameOrPath[0] != '\0');
1537 #if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1538 /* search module list for a match. */
1539 MODSTRUCT *module = &exe_module;
1542 if (dl_handle == module->dl_handle)
1544 /* found the handle. increment the refcount and return the
1545 existing module structure */
1546 TRACE("Found matching module %p for module name %s\n", module, libraryNameOrPath);
1548 if (module->refcount != -1)
1555 module = module->next;
1557 } while (module != &exe_module);
1560 TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath);
1562 module = LOADAllocModule(dl_handle, libraryNameOrPath);
1563 if (nullptr == module)
1565 ERROR("couldn't create new module\n");
1566 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1571 /* We now get the address of DllMain if the module contains one. */
1572 module->pDllMain = (PDLLMAIN)dlsym(module->dl_handle, "DllMain");
1574 /* Add the new module on to the end of the list */
1575 module->prev = exe_module.prev;
1576 module->next = &exe_module;
1577 exe_module.prev->next = module;
1578 exe_module.prev = module;
1580 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1581 module->inode = stat_buf.st_ino;
1582 module->device = stat_buf.st_dev;
1590 LOADRegisterLibraryDirect [internal]
1592 Registers a system handle to a loaded library with the module list.
1595 NATIVE_LIBRARY_HANDLE dl_handle: System handle to the loaded library.
1596 LPCSTR libraryNameOrPath: The library that was loaded.
1597 BOOL fDynamic: TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary.
1600 PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1602 static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic)
1604 MODSTRUCT *module = LOADAddModule(dl_handle, libraryNameOrPath);
1605 if (module == nullptr)
1610 /* If the module contains a DllMain, call it. */
1611 if (module->pDllMain)
1613 TRACE("Calling DllMain (%p) for module %S\n",
1615 module->lib_name ? module->lib_name : W16_NULLSTRING);
1617 if (nullptr == module->hinstance)
1619 PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
1620 if (registerModule != nullptr)
1622 module->hinstance = registerModule(libraryNameOrPath);
1626 // If the target module doesn't have the PAL_RegisterModule export, then use this PAL's
1627 // module handle assuming that the target module is referencing this PAL's exported
1628 // functions on said handle.
1629 module->hinstance = (HINSTANCE)module;
1633 BOOL dllMainRetVal = LOADCallDllMainSafe(module, DLL_PROCESS_ATTACH, fDynamic ? nullptr : (LPVOID)-1);
1635 // If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module
1638 ERROR("DllMain returned FALSE; unloading module.\n");
1639 module->pDllMain = nullptr;
1640 FreeLibrary((HMODULE)module);
1641 SetLastError(ERROR_DLL_INIT_FAILED);
1647 TRACE("Module does not contain a DllMain function.\n");
1655 LOADLoadLibrary [internal]
1657 implementation of LoadLibrary (for use by the A/W variants)
1660 LPSTR shortAsciiName : name of module as specified to LoadLibrary
1662 BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
1665 handle to loaded module
1668 static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
1670 HMODULE module = nullptr;
1671 NATIVE_LIBRARY_HANDLE dl_handle = nullptr;
1673 shortAsciiName = FixLibCName(shortAsciiName);
1677 dl_handle = LOADLoadLibraryDirect(shortAsciiName);
1680 module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic);
1689 LOADInitializeCoreCLRModule
1691 Run the initialization methods for CoreCLR module (the module containing this PAL).
1700 BOOL LOADInitializeCoreCLRModule()
1702 MODSTRUCT *module = LOADGetPalLibrary();
1705 ERROR("Can not load the PAL module\n");
1708 PDLLMAIN pRuntimeDllMain = (PDLLMAIN)dlsym(module->dl_handle, "CoreDllMain");
1709 if (!pRuntimeDllMain)
1711 ERROR("Can not find the CoreDllMain entry point\n");
1714 return pRuntimeDllMain(module->hinstance, DLL_PROCESS_ATTACH, nullptr);
1721 Load and initialize the PAL module.
1727 pointer to module struct
1730 MODSTRUCT *LOADGetPalLibrary()
1732 if (pal_module == nullptr)
1734 // Initialize the pal module (the module containing LOADGetPalLibrary). Assumes that
1735 // the PAL is linked into the coreclr module because we use the module name containing
1736 // this function for the coreclr path.
1737 TRACE("Loading module for PAL library\n");
1740 if (dladdr((PVOID)&LOADGetPalLibrary, &info) == 0)
1742 ERROR("LOADGetPalLibrary: dladdr() failed.\n");
1745 // Stash a copy of the CoreCLR installation path in a global variable.
1746 // Make sure it's terminated with a slash.
1747 if (g_szCoreCLRPath == nullptr)
1749 size_t cbszCoreCLRPath = strlen(info.dli_fname) + 1;
1750 g_szCoreCLRPath = (char*) InternalMalloc(cbszCoreCLRPath);
1752 if (g_szCoreCLRPath == nullptr)
1754 ERROR("LOADGetPalLibrary: InternalMalloc failed!");
1758 if (strcpy_s(g_szCoreCLRPath, cbszCoreCLRPath, info.dli_fname) != SAFECRT_SUCCESS)
1760 ERROR("LOADGetPalLibrary: strcpy_s failed!");
1765 pal_module = (MODSTRUCT *)LOADLoadLibrary(info.dli_fname, FALSE);
1777 Enter the critical section associated to the module list
1786 void LockModuleList()
1788 CPalThread * pThread =
1789 (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1791 InternalEnterCriticalSection(pThread, &module_critsec);
1799 Leave the critical section associated to the module list
1808 void UnlockModuleList()
1810 CPalThread * pThread =
1811 (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1813 InternalLeaveCriticalSection(pThread, &module_critsec);