127 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* 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;
 | |
| }
 |