OSDN Git Service

* dcrt0.cc (_dll_crt0): Fix formatting.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / dcrt0.cc
index 4ca3294..8b69939 100644 (file)
@@ -1,7 +1,7 @@
 /* dcrt0.cc -- essentially the main() for the Cygwin dll
 
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Red Hat, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -10,23 +10,18 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include "glob.h"
-#include "exceptions.h"
 #include <ctype.h>
-#include <limits.h>
-#include <winnls.h>
-#include <wingdi.h>
-#include <winuser.h>
+#include <locale.h>
+#include "environ.h"
 #include "sigproc.h"
 #include "pinfo.h"
 #include "cygerrno.h"
 #define NEED_VFORK
 #include "perprocess.h"
-#include "security.h"
 #include "path.h"
 #include "fhandler.h"
 #include "dtable.h"
@@ -36,98 +31,25 @@ details. */
 #include "shared_info.h"
 #include "cygwin_version.h"
 #include "dll_init.h"
-#include "sync.h"
 #include "heap.h"
-#include "environ.h"
+#include "tls_pbuf.h"
+#include "exception.h"
+#include "cygxdr.h"
+#include "fenv.h"
+#include "ntdll.h"
+#include "wow64.h"
 
 #define MAX_AT_FILE_LEVEL 10
 
 #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
 
 extern "C" void cygwin_exit (int) __attribute__ ((noreturn));
-
-HANDLE NO_COPY hMainProc = (HANDLE) -1;
-HANDLE NO_COPY hMainThread;
-HANDLE NO_COPY hProcToken;
-HANDLE NO_COPY hProcImpToken;
-
-muto NO_COPY lock_process::locker;
-
-bool display_title;
-bool strip_title_path;
-bool allow_glob = true;
-bool NO_COPY in_forkee;
-
-int __argc_safe;
-int _declspec(dllexport) __argc;
-char _declspec(dllexport) **__argv;
-#ifdef NEWVFORK
-vfork_save NO_COPY *main_vfork;
-#endif
-
-static int NO_COPY envc;
-char NO_COPY **envp;
-
 extern "C" void __sinit (_reent *);
 
-_cygtls NO_COPY *_main_tls;
-
-bool NO_COPY cygwin_finished_initializing;
-
-/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t.
-   This is subtracted from the signal number prior to shifting the bit.
-   In older versions of cygwin, the signal was used as-is to shift the
-   bit for masking.  So, we'll temporarily detect this and set it to zero
-   for programs that are linked using older cygwins.  This is just a stopgap
-   measure to allow an orderly transfer to the new, correct sigmask method. */
-unsigned NO_COPY int signal_shift_subtract = 1;
-
-MTinterface _mtinterf;
-
-bool NO_COPY _cygwin_testing;
-
-char NO_COPY almost_null[1];
-
-extern "C"
-{
-  /* This is an exported copy of environ which can be used by DLLs
-     which use cygwin.dll.  */
-  char **__cygwin_environ;
-  char ***main_environ = &__cygwin_environ;
-  /* __progname used in getopt error message */
-  char *__progname;
-  struct per_process __cygwin_user_data =
-  {/* initial_sp */ 0, /* magic_biscuit */ 0,
-   /* dll_major */ CYGWIN_VERSION_DLL_MAJOR,
-   /* dll_major */ CYGWIN_VERSION_DLL_MINOR,
-   /* impure_ptr_ptr */ NULL, /* envptr */ NULL,
-   /* malloc */ malloc, /* free */ free,
-   /* realloc */ realloc,
-   /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL,
-   /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL,
-   /* bss_start */ NULL, /* bss_end */ NULL,
-   /* calloc */ calloc,
-   /* premain */ {NULL, NULL, NULL, NULL},
-   /* run_ctors_p */ 0,
-   /* unused */ {0, 0, 0, 0, 0, 0, 0},
-   /* UNUSED forkee */ 0,
-   /* hmodule */ NULL,
-   /* api_major */ CYGWIN_VERSION_API_MAJOR,
-   /* api_minor */ CYGWIN_VERSION_API_MINOR,
-   /* unused2 */ {0, 0, 0, 0, 0, 0},
-   /* threadinterface */ &_mtinterf,
-   /* impure_ptr */ _GLOBAL_REENT,
-  };
-  bool ignore_case_with_glob;
-  int __declspec (dllexport) _check_for_executable = true;
-#ifdef DEBUGGING
-  int pinger;
-#endif
-  int NO_COPY __api_fatal_exit_val = 1;
-};
+static int NO_COPY envc;
+static char NO_COPY **envp;
 
-char *old_title;
-char title_buf[TITLESIZE + 1];
+bool NO_COPY jit_debug;
 
 static void
 do_global_dtors ()
@@ -169,14 +91,17 @@ insert_file (char *name, char *&cmd)
 {
   HANDLE f;
   DWORD size;
-
-  f = CreateFile (name + 1,
-                 GENERIC_READ,          /* open for reading    */
-                 FILE_SHARE_READ,       /* share for reading   */
-                 &sec_none_nih,         /* no security         */
-                 OPEN_EXISTING,         /* existing file only  */
-                 FILE_ATTRIBUTE_NORMAL, /* normal file         */
-                 NULL);                 /* no attr. template   */
+  tmp_pathbuf tp;
+
+  PWCHAR wname = tp.w_get ();
+  sys_mbstowcs (wname, NT_MAX_PATH, name + 1);
+  f = CreateFileW (wname,
+                  GENERIC_READ,                /* open for reading     */
+                  FILE_SHARE_VALID_FLAGS,      /* share for reading    */
+                  &sec_none_nih,               /* default security     */
+                  OPEN_EXISTING,               /* existing file only   */
+                  FILE_ATTRIBUTE_NORMAL,       /* normal file          */
+                  NULL);                       /* no attr. template    */
 
   if (f == INVALID_HANDLE_VALUE)
     {
@@ -307,7 +232,15 @@ globify (char *word, char **&argv, int &argc, int &argvlen)
            else if (s[1] == quote || s[1] == '\\')
              s++;
            *p++ = '\\';
-           *p++ = *s;
+           size_t cnt = isascii (*s) ? 1 : mbtowc (NULL, s, MB_CUR_MAX);
+           if (cnt <= 1 || cnt == (size_t)-1)
+             *p++ = *s;
+           else
+             {
+               --s;
+               while (cnt-- > 0)
+                 *p++ = *++s;
+             }
          }
        if (*s == quote)
          p--;
@@ -444,64 +377,57 @@ check_sanity_and_sync (per_process *p)
     api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d > %d",
               p->api_major, cygwin_version.api_major);
 
-  if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <=
-      CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK)
-    signal_shift_subtract = 0;
+  /* This is a kludge to work around a version of _cygwin_common_crt0
+     which overwrote the cxx_malloc field with the local DLL copy.
+     Hilarity ensues if the DLL is not loaded while the process
+     is forking. */
+  __cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc;
 }
 
 child_info NO_COPY *child_proc_info = NULL;
 
-#define CYGWIN_GUARD (PAGE_EXECUTE_READWRITE | PAGE_GUARD)
+#define CYGWIN_GUARD (PAGE_READWRITE | PAGE_GUARD)
 
 void
 child_info_fork::alloc_stack_hard_way (volatile char *b)
 {
-  void *new_stack_pointer;
-  MEMORY_BASIC_INFORMATION m;
-  void *newbase;
-  int newlen;
-  bool guard;
-
-  if (!VirtualQuery ((LPCVOID) &b, &m, sizeof m))
-    api_fatal ("fork: couldn't get stack info, %E");
-
-  LPBYTE curbot = (LPBYTE) m.BaseAddress + m.RegionSize;
-
-  if (stacktop > (LPBYTE) m.AllocationBase && stacktop < curbot)
-    {
-      newbase = curbot;
-      newlen = (LPBYTE) stackbottom - (LPBYTE) curbot;
-      guard = false;
-    }
-  else
-    {
-      newbase = (LPBYTE) stacktop - (128 * 1024);
-      newlen = (LPBYTE) stackbottom - (LPBYTE) newbase;
-      guard = true;
-    }
+  void *stack_ptr;
+  DWORD stacksize;
+
+  /* First check if the requested stack area is part of the user heap
+     or part of a mmapped region.  If so, we have been started from a
+     pthread with an application-provided stack, and the stack has just
+     to be used as is. */
+  if ((stacktop >= cygheap->user_heap.base
+      && stackbottom <= cygheap->user_heap.max)
+      || is_mmapped_region ((caddr_t) stacktop, (caddr_t) stackbottom))
+    return;
 
-  if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
+  /* First, try to reserve the entire stack. */
+  stacksize = (char *) stackbottom - (char *) stackaddr;
+  if (!VirtualAlloc (stackaddr, stacksize, MEM_RESERVE, PAGE_NOACCESS))
     api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
-               stacktop, stackbottom);
-  new_stack_pointer = (void *) ((LPBYTE) stackbottom - (stacksize += 8192));
-  if (!VirtualAlloc (new_stack_pointer, stacksize, MEM_COMMIT,
-                    PAGE_EXECUTE_READWRITE))
-    api_fatal ("fork: can't commit memory for stack %p(%d), %E",
-              new_stack_pointer, stacksize);
-  if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
-    api_fatal ("fork: couldn't get new stack info, %E");
-
-  if (guard)
+              stackaddr, stackbottom);
+  stacksize = (char *) stackbottom - (char *) stacktop;
+  stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT, PAGE_READWRITE);
+  if (!stack_ptr)
+    abort ("can't commit memory for stack %p(%d), %E", stacktop, stacksize);
+  if (guardsize != (size_t) -1)
     {
-      m.BaseAddress = (LPBYTE) m.BaseAddress - 1;
-      if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
-                        CYGWIN_GUARD))
-       api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
-                  m.BaseAddress);
+      /* Allocate PAGE_GUARD page if it still fits. */
+      if (stack_ptr > stackaddr)
+       {
+         stack_ptr = (void *) ((LPBYTE) stack_ptr
+                                       - wincap.page_size ());
+         if (!VirtualAlloc (stack_ptr, wincap.page_size (), MEM_COMMIT,
+                            CYGWIN_GUARD))
+           api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
+                      stack_ptr);
+       }
+      /* Allocate POSIX guard pages. */
+      if (guardsize > 0)
+       VirtualAlloc (stackaddr, guardsize, MEM_COMMIT, PAGE_NOACCESS);
     }
-  if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
-    api_fatal ("fork: couldn't get new stack info, %E");
-  stacktop = m.BaseAddress;
   b[0] = '\0';
 }
 
@@ -521,14 +447,29 @@ child_info_fork::alloc_stack ()
 {
   volatile char * volatile esp;
   __asm__ volatile ("movl %%esp,%0": "=r" (esp));
-  if (_tlsbase != stackbottom)
+  /* Make sure not to try a hard allocation if we have been forked off from
+     the main thread of a Cygwin process which has been started from a 64 bit
+     parent.  In that case the _tlsbase of the forked child is not the same
+     as the _tlsbase of the parent (== stackbottom), but only because the
+     stack of the parent has been slightly rearranged.  See comment in
+     wow64_revert_to_original_stack for details. We check here if the
+     parent stack fits into the child stack. */
+  if (_tlsbase != stackbottom
+      && (!wincap.is_wow64 ()
+         || stacktop < (char *) NtCurrentTeb ()->DeallocationStack
+         || stackbottom > _tlsbase))
     alloc_stack_hard_way (esp);
   else
     {
       char *st = (char *) stacktop - 4096;
       while (_tlstop >= st)
        esp = getstack (esp);
-      stacksize = 0;
+      stackaddr = 0;
+      /* This only affects forked children of a process started from a native
+         64 bit process, but it doesn't hurt to do it unconditionally.  Fix
+        StackBase in the child to be the same as in the parent, so that the
+        computation of _my_tls is correct. */
+      _tlsbase = (char *) stackbottom;
     }
 }
 
@@ -544,22 +485,13 @@ break_here ()
 static void
 initial_env ()
 {
-  char buf[NT_MAX_PATH];
-  if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+  if (GetEnvironmentVariableA ("CYGWIN_TESTING", NULL, 0))
     _cygwin_testing = 1;
 
 #ifdef DEBUGGING
   DWORD len;
-
-  if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
-    {
-      DWORD ms = atoi (buf);
-      console_printf ("Sleeping %d, pid %u %P\n", ms, GetCurrentProcessId ());
-      Sleep (ms);
-      if (!strace.active () && !dynamically_loaded)
-       strace.hello ();
-    }
-  if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
+  char buf[NT_MAX_PATH];
+  if (GetEnvironmentVariableA ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
     {
       char buf1[NT_MAX_PATH];
       len = GetModuleFileName (NULL, buf1, NT_MAX_PATH);
@@ -573,13 +505,13 @@ initial_env ()
       if (strstr (buf1, buf))
        {
          error_start_init (p);
+         jit_debug = true;
          try_to_debug ();
          console_printf ("*** Sending Break.  gdb may issue spurious SIGTRAP message.\n");
          break_here ();
        }
     }
 #endif
-
 }
 
 child_info *
@@ -592,7 +524,10 @@ get_cygwin_startup_info ()
 
   if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res
       || res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC)
-    res = NULL;
+    {
+      strace.activate (false);
+      res = NULL;
+    }
   else
     {
       if ((res->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
@@ -604,12 +539,12 @@ get_cygwin_startup_info ()
       unsigned should_be_cb = 0;
       switch (res->type)
        {
-         case _PROC_FORK:
+         case _CH_FORK:
            in_forkee = true;
            should_be_cb = sizeof (child_info_fork);
            /* fall through */;
-         case _PROC_SPAWN:
-         case _PROC_EXEC:
+         case _CH_SPAWN:
+         case _CH_EXEC:
            if (!should_be_cb)
              should_be_cb = sizeof (child_info_spawn);
            if (should_be_cb != res->cb)
@@ -618,16 +553,15 @@ get_cygwin_startup_info ()
              multiple_cygwin_problem ("fhandler size", res->fhandler_union_cb, sizeof (fhandler_union));
            if (res->isstraced ())
              {
-               res->ready (false);
-               for (unsigned i = 0; !being_debugged () && i < 10000; i++)
-                 low_priority_sleep (0);
-               strace.hello ();
+               while (!being_debugged ())
+                 yield ();
+               strace.activate (res->type == _CH_FORK);
              }
            break;
          default:
            system_printf ("unknown exec type %d", res->type);
            /* intentionally fall through */
-         case _PROC_WHOOPS:
+         case _CH_WHOOPS:
            res = NULL;
            break;
        }
@@ -645,8 +579,8 @@ void
 child_info_fork::handle_fork ()
 {
   cygheap_fixup_in_child (false);
-  memory_init ();
-  set_myself (NULL);
+  memory_init (false);
+  myself.thisproc (NULL);
   myself->uid = cygheap->user.real_uid;
   myself->gid = cygheap->user.real_gid;
 
@@ -655,6 +589,12 @@ child_info_fork::handle_fork ()
              "dll bss", dll_bss_start, dll_bss_end,
              "user heap", cygheap->user_heap.base, cygheap->user_heap.ptr,
              NULL);
+
+  /* Do the relocations here.  These will actually likely be overwritten by the
+     below child_copy but we do them here in case there is a read-only section
+     which does not get copied by fork. */
+  _pei386_runtime_relocator (user_data);
+
   /* step 2 now that the dll has its heap filled in, we can fill in the
      user's data and bss since user_data is now filled out. */
   child_copy (parent, false,
@@ -669,14 +609,16 @@ child_info_fork::handle_fork ()
 void
 child_info_spawn::handle_spawn ()
 {
+  extern void fixup_lockf_after_exec ();
   HANDLE h;
   cygheap_fixup_in_child (true);
-  memory_init ();
+  memory_init (false);
   if (!moreinfo->myself_pinfo ||
-      !DuplicateHandle (hMainProc, moreinfo->myself_pinfo, hMainProc, &h, 0,
+      !DuplicateHandle (GetCurrentProcess (), moreinfo->myself_pinfo,
+                       GetCurrentProcess (), &h, 0,
                        FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
     h = NULL;
-  set_myself (h);
+  myself.thisproc (h);
   __argc = moreinfo->argc;
   __argv = moreinfo->argv;
   envp = moreinfo->envp;
@@ -687,6 +629,13 @@ child_info_spawn::handle_spawn ()
     cygheap->fdtab.move_fd (__stdin, 0);
   if (__stdout >= 0)
     cygheap->fdtab.move_fd (__stdout, 1);
+  cygheap->user.groups.clear_supp ();
+
+  /* If we're execing we may have "inherited" a list of children forked by the
+     previous process executing under this pid.  Reattach them here so that we
+     can wait for them.  */
+  if (type == _CH_EXEC)
+    reattach_children ();
 
   ready (true);
 
@@ -696,25 +645,42 @@ child_info_spawn::handle_spawn ()
   child_proc_info->parent = NULL;
 
   signal_fixup_after_exec ();
-  if (moreinfo->old_title)
+  fixup_lockf_after_exec ();
+}
+
+/* Retrieve and store system directory for later use.  Note that the
+   directory is stored with a trailing backslash! */
+static void
+init_windows_system_directory ()
+{
+  if (!windows_system_directory_length)
     {
-      old_title = strcpy (title_buf, moreinfo->old_title);
-      cfree (moreinfo->old_title);
+      windows_system_directory_length =
+           GetSystemDirectoryW (windows_system_directory, MAX_PATH);
+      if (windows_system_directory_length == 0)
+       api_fatal ("can't find windows system directory");
+      windows_system_directory[windows_system_directory_length++] = L'\\';
+      windows_system_directory[windows_system_directory_length] = L'\0';
+
+      system_wow64_directory_length =
+       GetSystemWow64DirectoryW (system_wow64_directory, MAX_PATH);
+      if (system_wow64_directory_length)
+       {
+         system_wow64_directory[system_wow64_directory_length++] = L'\\';
+         system_wow64_directory[system_wow64_directory_length] = L'\0';
+       }
     }
 }
 
-void __stdcall
+void
 dll_crt0_0 ()
 {
+  child_proc_info = get_cygwin_startup_info ();
+  init_windows_system_directory ();
   init_global_security ();
   initial_env ();
 
-  SetErrorMode (SEM_FAILCRITICALERRORS);
-
-  /* Initialize signal processing here, early, in the hopes that the creation
-     of a thread early in the process will cause more predictability in memory
-     layout for the main thread. */
-  sigproc_init ();
+  SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
 
   lock_process::init ();
   _impure_ptr = _GLOBAL_REENT;
@@ -725,34 +691,36 @@ dll_crt0_0 ()
   user_data->impure_ptr = _impure_ptr;
   user_data->impure_ptr_ptr = &_impure_ptr;
 
-  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
-                      GetCurrentProcess (), &hMainProc, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS))
-    hMainProc = GetCurrentProcess ();
+  DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+                  GetCurrentProcess (), &hMainThread,
+                  0, false, DUPLICATE_SAME_ACCESS);
 
-  DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
-                  &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
-
-  OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
+  NtOpenProcessToken (NtCurrentProcess (), MAXIMUM_ALLOWED, &hProcToken);
   set_cygwin_privileges (hProcToken);
 
   device::init ();
   do_global_ctors (&__CTOR_LIST__, 1);
   cygthread::init ();
 
-  child_proc_info = get_cygwin_startup_info ();
   if (!child_proc_info)
-    memory_init ();
+    {
+      memory_init (true);
+      /* WOW64 process?  Check if we have been started from 64 bit process
+         and if our stack is at an unusual address.  Set wow64_has_64bit_parent
+        if so.  Problem description in wow64_test_for_64bit_parent. */
+      if (wincap.is_wow64 ())
+       wow64_has_64bit_parent = wow64_test_for_64bit_parent ();
+    }
   else
     {
       cygwin_user_h = child_proc_info->user_h;
       switch (child_proc_info->type)
        {
-         case _PROC_FORK:
+         case _CH_FORK:
            fork_info->handle_fork ();
            break;
-         case _PROC_SPAWN:
-         case _PROC_EXEC:
+         case _CH_SPAWN:
+         case _CH_EXEC:
            spawn_info->handle_spawn ();
            break;
        }
@@ -766,7 +734,13 @@ dll_crt0_0 ()
   events_init ();
   tty_list::init_session ();
 
-  cygheap->cwd.init ();
+  _main_tls = &_my_tls;
+
+  /* Initialize signal processing here, early, in the hopes that the creation
+     of a thread early in the process will cause more predictability in memory
+     layout for the main thread. */
+  if (!dynamically_loaded)
+    sigproc_init ();
 
   debug_printf ("finished dll_crt0_0 initialization");
 }
@@ -778,22 +752,47 @@ dll_crt0_0 ()
 void
 dll_crt0_1 (void *)
 {
+  extern void initial_setlocale ();
+
+  if (dynamically_loaded)
+    sigproc_init ();
+
   check_sanity_and_sync (user_data);
+
+  /* Initialize malloc and then call user_shared_initialize since it relies
+     on a functioning malloc and it's possible that the user's program may
+     have overridden malloc.  We only know about that at this stage,
+     unfortunately. */
   malloc_init ();
-#ifdef CGF
+  user_shared->initialize ();
+
+#ifdef CYGHEAP_DEBUG
   int i = 0;
   const int n = 2 * 1024 * 1024;
   while (i--)
-    small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n));
+    {
+      void *p = cmalloc (HEAP_STR, n);
+      if (p)
+       small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n));
+      else
+       {
+         small_printf ("total allocated %p\n", (i - 1) * n);
+         break;
+       }
+    }
 #endif
 
-  ProtectHandle (hMainProc);
   ProtectHandle (hMainThread);
 
+  cygheap->cwd.init ();
+
   /* Initialize pthread mainthread when not forked and it is safe to call new,
      otherwise it is reinitalized in fixup_after_fork */
   if (!in_forkee)
-    pthread::init_mainthread ();
+    {
+      pthread::init_mainthread ();
+      _pei386_runtime_relocator (user_data);
+    }
 
 #ifdef DEBUGGING
   strace.microseconds ();
@@ -820,16 +819,17 @@ dll_crt0_1 (void *)
 
         NOTE: Don't do anything that involves the stack until you've completed
         this step. */
-      if (fork_info->stacksize)
+      if (fork_info->stackaddr)
        {
          _tlsbase = (char *) fork_info->stackbottom;
          _tlstop = (char *) fork_info->stacktop;
-         _my_tls.init_exception_handler (_cygtls::handle_exceptions);
        }
 
       longjmp (fork_info->jmp, true);
     }
 
+  __sinit (_impure_ptr);
+
 #ifdef DEBUGGING
   {
   extern void fork_init ();
@@ -837,23 +837,19 @@ dll_crt0_1 (void *)
   }
 #endif
   pinfo_init (envp, envc);
-
-  if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
-    old_title = title_buf;
+  strace.dll_info ();
 
   /* Allocate cygheap->fdtab */
   dtable_init ();
 
   uinfo_init ();       /* initialize user info */
 
-  wait_for_sigthread ();
-  extern DWORD threadfunc_ix;
-  if (!threadfunc_ix)
-    system_printf ("internal error: couldn't determine location of thread function on stack.  Expect signal problems.");
-
   /* Connect to tty. */
   tty::init_session ();
 
+  /* Set internal locale to the environment settings. */
+  initial_setlocale ();
+
   if (!__argc)
     {
       PWCHAR wline = GetCommandLineW ();
@@ -871,7 +867,8 @@ dll_crt0_1 (void *)
       if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\')))
        {
          char *new_argv0 = (char *) malloc (NT_MAX_PATH);
-         cygwin_conv_to_posix_path (__argv[0], new_argv0);
+         cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, __argv[0],
+                           new_argv0, NT_MAX_PATH);
          __argv[0] = (char *) realloc (new_argv0, strlen (new_argv0) + 1);
        }
     }
@@ -889,6 +886,8 @@ dll_crt0_1 (void *)
     ++__progname;
   else
     __progname = __argv[0];
+  program_invocation_name = __argv[0];
+  program_invocation_short_name = __progname;
   if (__progname)
     {
       char *cp = strchr (__progname, '\0') - 4;
@@ -896,18 +895,7 @@ dll_crt0_1 (void *)
        *cp = '\0';
     }
 
-  /* Set new console title if appropriate. */
-
-  if (display_title && !dynamically_loaded)
-    {
-      char *cp = __progname;
-      if (strip_title_path)
-       for (char *ptr = cp; *ptr && *ptr != ' '; ptr++)
-         if (isdirsep (*ptr))
-           cp = ptr + 1;
-      set_console_title (cp);
-    }
-
+  (void) xdr_set_vprintf (&cygxdr_vwarnx);
   cygwin_finished_initializing = true;
   /* Call init of loaded dlls. */
   dlls.init ();
@@ -917,40 +905,83 @@ dll_crt0_1 (void *)
     for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++)
       user_data->premain[i] (__argc, __argv, user_data);
 
-  debug_printf ("user_data->main %p", user_data->main);
+  set_errno (0);
 
   if (dynamically_loaded)
     {
-      set_errno (0);
+      _setlocale_r (_REENT, LC_CTYPE, "C");
       return;
     }
 
   /* Disable case-insensitive globbing */
   ignore_case_with_glob = false;
 
-  set_errno (0);
-
   MALLOC_CHECK;
   cygbench (__progname);
 
-  /* Flush signals and ensure that signal thread is up and running. Can't
-     do this for noncygwin case since the signal thread is blocked due to
-     LoadLibrary serialization. */
   ld_preload ();
+  /* Per POSIX set the default application locale back to "C". */
+  _setlocale_r (_REENT, LC_CTYPE, "C");
+
   if (user_data->main)
-    cygwin_exit (user_data->main (__argc, __argv, *user_data->envptr));
+    {
+      /* Create a copy of Cygwin's version of __argv so that, if the user makes
+        a change to an element of argv[] it does not affect Cygwin's argv.
+        Changing the the contents of what argv[n] points to will still
+        affect Cygwin.  This is similar (but not exactly like) Linux. */
+      char *newargv[__argc + 1];
+      char **nav = newargv;
+      char **oav = __argv;
+      while ((*nav++ = *oav++) != NULL)
+       continue;
+      cygwin_exit (user_data->main (__argc, newargv, *user_data->envptr));
+    }
+  __asm__ ("                           \n\
+       .global __cygwin_exit_return    \n\
+__cygwin_exit_return:                  \n\
+");
 }
 
 extern "C" void __stdcall
 _dll_crt0 ()
 {
+  /* Handle WOW64 process started from native 64 bit process.  See comment
+     in wow64_test_for_64bit_parent for a full problem description. */
+  if (wow64_has_64bit_parent && !dynamically_loaded)
+    {
+      /* Must be static since it's referenced after the stack pointers have
+        been moved. */
+      static PVOID allocationbase = 0;
+
+      /* Check if we just move the stack.  See comment in
+        wow64_revert_to_original_stack for the gory details. */
+      PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
+      if (stackaddr)
+       {
+         /* 2nd half of the stack move.  Set stack pointers to new address. */
+         __asm__ ("\n\
+                  movl  %[ADDR], %%esp \n\
+                  movl  %%esp, %%ebp   \n"
+                  : : [ADDR] "r" (stackaddr));
+         /* Now we're back on the original stack.  Free up space taken by the
+            former main thread stack and set DeallocationStack correctly. */
+         VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
+         NtCurrentTeb ()->DeallocationStack = allocationbase;
+       }
+      else
+       /* Fall back to respawn if wow64_revert_to_original_stack fails. */
+       wow64_respawn_process ();
+    }
+#ifdef __i386__
+  _feinitialise ();
+#endif
   main_environ = user_data->envptr;
   if (in_forkee)
-    fork_info->alloc_stack ();
-  else
-    __sinit (_impure_ptr);
+    {
+      fork_info->alloc_stack ();
+      _main_tls = &_my_tls;
+    }
 
-  _main_tls = &_my_tls;
   _main_tls->call ((DWORD (*) (void *, void *)) dll_crt0_1, NULL);
 }
 
@@ -991,12 +1022,21 @@ cygwin_dll_init ()
 extern "C" void
 __main (void)
 {
+  /* Ordering is critical here.  DLL ctors have already been
+     run as they were being loaded, so we should stack the
+     queued call to DLL dtors now.  */
+  atexit (dll_global_dtors);
   do_global_ctors (user_data->ctors, false);
+  /* Now we have run global ctors, register their dtors.
+
+     At exit, global dtors will run first, so the app can still
+     use shared library functions while terminating; then the
+     DLLs will be destroyed; finally newlib will shut down stdio
+     and terminate itself.  */
   atexit (do_global_dtors);
+  sig_dispatch_pending (true);
 }
 
-exit_states NO_COPY exit_state;
-
 void __stdcall
 do_exit (int status)
 {
@@ -1013,25 +1053,12 @@ do_exit (int status)
 
   lock_process until_exit (true);
 
-  if (exit_state < ES_GLOBAL_DTORS)
-    {
-      exit_state = ES_GLOBAL_DTORS;
-      dll_global_dtors ();
-    }
-
   if (exit_state < ES_EVENTS_TERMINATE)
     {
       exit_state = ES_EVENTS_TERMINATE;
       events_terminate ();
     }
 
-  UINT n = (UINT) status;
-  if (exit_state < ES_THREADTERM)
-    {
-      exit_state = ES_THREADTERM;
-      cygthread::terminate ();
-    }
-
   if (exit_state < ES_SIGNAL)
     {
       exit_state = ES_SIGNAL;
@@ -1047,6 +1074,13 @@ do_exit (int status)
       close_all_files ();
     }
 
+  UINT n = (UINT) status;
+  if (exit_state < ES_THREADTERM)
+    {
+      exit_state = ES_THREADTERM;
+      cygthread::terminate ();
+    }
+
   myself->stopsig = 0;
 
   if (exit_state < ES_HUP_PGRP)
@@ -1081,42 +1115,22 @@ do_exit (int status)
 
     }
 
-  if (exit_state < ES_TITLE)
-    {
-      exit_state = ES_TITLE;
-      /* restore console title */
-      if (old_title && display_title)
-       set_console_title (old_title);
-    }
-
-  if (exit_state < ES_TTY_TERMINATE)
-    {
-      exit_state = ES_TTY_TERMINATE;
-      cygwin_shared->tty.terminate ();
-    }
-
   myself.exit (n);
 }
 
-static NO_COPY muto atexit_lock;
-
 extern "C" int
-cygwin_atexit (void (*function)(void))
+cygwin_atexit (void (*fn) (void))
 {
   int res;
-  atexit_lock.init ("atexit_lock");
-  atexit_lock.acquire ();
-  res = atexit (function);
-  atexit_lock.release ();
+  dll *d = dlls.find ((void *) _my_tls.retaddr ());
+  res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d) : atexit (fn);
   return res;
 }
 
 extern "C" void
 cygwin_exit (int n)
 {
-  dll_global_dtors ();
-  if (atexit_lock)
-    atexit_lock.acquire ();
+  exit_state = ES_EXIT_STARTING;
   exit (n);
 }
 
@@ -1126,14 +1140,13 @@ _exit (int n)
   do_exit (((DWORD) n & 0xff) << 8);
 }
 
+extern "C" void cygwin_stackdump ();
+
 extern "C" void
-__api_fatal (const char *fmt, ...)
+vapi_fatal (const char *fmt, va_list ap)
 {
   char buf[4096];
-  va_list ap;
-
-  va_start (ap, fmt);
-  int n = __small_sprintf (buf, "%P: *** fatal error - ");
+  int n = __small_sprintf (buf, "%P: *** fatal error %s- ", in_forkee ? "in forked process " : "");
   __small_vsprintf (buf + n, fmt, ap);
   va_end (ap);
   strace.prntf (_STRACE_SYSTEM, NULL, "%s", buf);
@@ -1141,20 +1154,29 @@ __api_fatal (const char *fmt, ...)
 #ifdef DEBUGGING
   try_to_debug ();
 #endif
+  cygwin_stackdump ();
   myself.exit (__api_fatal_exit_val);
 }
 
+extern "C" void
+api_fatal (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  vapi_fatal (fmt, ap);
+}
+
 void
 multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version)
 {
   if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap")))
     {
-      child_proc_info->type = _PROC_WHOOPS;
+      child_proc_info->type = _CH_WHOOPS;
       return;
     }
 
-  char buf[1024];
-  if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf)))
+  if (GetEnvironmentVariableA ("CYGWIN_MISMATCH_OK", NULL, 0))
     return;
 
   if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version)
@@ -1174,8 +1196,7 @@ are unable to find another cygwin DLL.",
 void __stdcall
 cygbench (const char *s)
 {
-  char buf[1024];
-  if (GetEnvironmentVariable ("CYGWIN_BENCH", buf, sizeof (buf)))
+  if (GetEnvironmentVariableA ("CYGWIN_BENCH", NULL, 0))
     small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ());
 }
 #endif