/* init.cc This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include "cygtls.h" #include "ntdll.h" #include "shared_info.h" static DWORD _my_oldfunc; static char *search_for = (char *) cygthread::stub; unsigned threadfunc_ix[8]; static bool dll_finished_loading; #define OLDFUNC_OFFSET -1 static void WINAPI threadfunc_fe (VOID *arg) { #ifdef __i386__ #if __GNUC_PREREQ(6,0) #pragma GCC diagnostic ignored "-Wframe-address" #endif (void)__builtin_return_address(1); #if __GNUC_PREREQ(6,0) #pragma GCC diagnostic pop #endif asm volatile ("andl $-16,%%esp" ::: "%esp"); #endif _cygtls::call ((DWORD (*) (void *, void *)) TlsGetValue (_my_oldfunc), arg); } /* If possible, redirect the thread entry point to a cygwin routine which adds tls stuff to the stack. */ static void munge_threadfunc () { int i; char **ebp = (char **) __builtin_frame_address (0); if (!threadfunc_ix[0]) { char **peb; char **top = (char **) NtCurrentTeb()->Tib.StackBase; for (peb = ebp, i = 0; peb < top && i < 7; peb++) if (*peb == search_for) threadfunc_ix[i++] = peb - ebp; if (0 && !threadfunc_ix[0]) { try_to_debug (); return; } } if (threadfunc_ix[0]) { char *threadfunc = NULL; NtQueryInformationThread (NtCurrentThread (), ThreadQuerySetWin32StartAddress, &threadfunc, sizeof threadfunc, NULL); if (!search_for || threadfunc == search_for) { search_for = NULL; for (i = 0; threadfunc_ix[i]; i++) if (!threadfunc || ebp[threadfunc_ix[i]] == threadfunc) ebp[threadfunc_ix[i]] = (char *) threadfunc_fe; TlsSetValue (_my_oldfunc, threadfunc); } } } void dll_crt0_0 (); /* Non-static fake variable so GCC doesn't second-guess if we *really* need the alloca'd space in the DLL_PROCESS_ATTACH case below... */ void *alloca_dummy; extern "C" BOOL WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load) { BOOL test_stack_marker; switch (reason) { case DLL_PROCESS_ATTACH: init_console_handler (false); cygwin_hmodule = (HMODULE) h; dynamically_loaded = (static_load == NULL); /* Starting with adding the POSIX-1.2008 per-thread locale functionality, we need an initalized _REENT area even for the functions called from dll_crt0_0. Most importantly, we need the _REENT->_locale pointer initialized to NULL, so subsequent calls to locale-specific functions will always fall back to __global_locale, rather then crash due to _REENT->_locale having an arbitrary value. */ alloca_dummy = alloca (CYGTLS_PADSIZE); memcpy (_REENT, _GLOBAL_REENT, sizeof (struct _reent)); dll_crt0_0 (); _my_oldfunc = TlsAlloc (); dll_finished_loading = true; break; case DLL_PROCESS_DETACH: if (dynamically_loaded) shared_destroy (); break; case DLL_THREAD_ATTACH: if (dll_finished_loading) munge_threadfunc (); break; case DLL_THREAD_DETACH: if (dll_finished_loading && (PVOID) &_my_tls > (PVOID) &test_stack_marker && _my_tls.isinitialized ()) _my_tls.remove (0); break; } return TRUE; }