crt: Do not use atexit() for calling gcc global destructors in DLL builds

Function atexit() for DLL libraries is provided by mingw-w64, which is
statically linked on demand when needed.

Global destructors for DLL libraries are currently called via first
registered DLL atexit callback and atexit callbacks are executed explicitly
from the DLL entry point (for process detach event) in reverse order.

Execution of global destructors does not require DLL atexit support, so
call them explicitly after the invocation of atexit callbacks.

Provide two new functions __mingw_dll_do_global_ctors() and
__mingw_dll_do_global_dtors() which are suitable only for DLL builds.

__mingw_dll_do_global_ctors() is doing same thing as __main() except it
does not register atexit callback for dtors. It contains guard which
prevents executing globacl constructor multiple times.

__mingw_dll_do_global_dtors() is doing exactly same thing as
atexit callback __do_global_dtors(), just is called explictly.

Both functions __mingw_dll_do_global_ctors() and __mingw_dll_do_global_dtors()
must be separated from the compilation unit which provides __main symbol to
prevent linker referencing the atexit symbol. For this purpose provide
these two new functions via mingw_dll_ctors_dtors.c compilation unit.
And to prevent code duplicate at source level, define its functionality
directly in the gccmain.c with the preprocessor condition.

Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 397a8fb..85ba329 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -119,6 +119,7 @@
 src_libdloadhelper=libsrc/dloadhelper.c misc/delay-f.c
 
 src_libmingw32=include/internal.h include/sect_attribs.h crt/seh_signal_dispatcher.h \
+  crt/mingw_dll_ctors_dtors.c \
   crt/crtexewin.c     crt/dll_argv.c  crt/gccmain.c     crt/natstart.c  crt/pseudo-reloc-list.c  crt/wildcard.c \
   crt/charmax.c       crt/ucrtexewin.c crt/dllargv.c    crt/_newmode.c  crt/tlssup.c             crt/xncommod.c \
   crt/cinitexe.c      crt/merr.c      crt/pesect.c      crt/udllargc.c  crt/xthdloc.c \
diff --git a/mingw-w64-crt/crt/crtdll.c b/mingw-w64-crt/crt/crtdll.c
index 65dca8d..31a137f 100644
--- a/mingw-w64-crt/crt/crtdll.c
+++ b/mingw-w64-crt/crt/crtdll.c
@@ -17,7 +17,8 @@
 #include <sect_attribs.h>
 #include <locale.h>
 
-extern void __main ();
+extern void __cdecl __mingw_dll_do_global_ctors (void);
+extern void __cdecl __mingw_dll_do_global_dtors (void);
 extern void _pei386_runtime_relocator (void);
 extern _PIFV __xi_a[];
 extern _PIFV __xi_z[];
@@ -96,7 +97,7 @@
 	  if (ret != 0)
 	    goto i__leave;
 	  _initterm (__xc_a, __xc_z);
-	  __main ();
+	  __mingw_dll_do_global_ctors ();
 
 	  __native_startup_state = __initialized;
 	}
@@ -145,6 +146,7 @@
 	    __mingw_atexit_tls_callback_ptr (hDllHandle, dwReason, lpreserved);
 	  if (__mingw_dll_atexit_table_func_ptr != NULL)
 	    __mingw_dll_atexit_table_func_ptr (1 /*execute*/);
+	  __mingw_dll_do_global_dtors ();
 
 	  __native_startup_state = __uninitialized;
 	}
diff --git a/mingw-w64-crt/crt/gccmain.c b/mingw-w64-crt/crt/gccmain.c
index de1cf0e..2954f71 100644
--- a/mingw-w64-crt/crt/gccmain.c
+++ b/mingw-w64-crt/crt/gccmain.c
@@ -4,11 +4,14 @@
  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
  */
 
+#ifndef _MINGW_DLL_
 int __cdecl atexit (void (__cdecl *)(void));
+#endif
 typedef void (*func_ptr) (void);
 extern func_ptr __CTOR_LIST__[];
 extern func_ptr __DTOR_LIST__[];
 
+#ifndef _MINGW_DLL_
 /* WARNING: All these functions must be in one translation unit.
  * Otherwise linker can throw error "multiple definitions of __do_global_dtors"
  * when linking with static libgcc library which also provides these symbols.
@@ -16,6 +19,10 @@
 void __do_global_dtors (void);
 void __do_global_ctors (void);
 void __main (void);
+#else
+void __cdecl __mingw_dll_do_global_dtors (void);
+void __cdecl __mingw_dll_do_global_ctors (void);
+#endif
 
 /* __do_global_dtors is gcc ABI function which has to be exported.
  * It executes all gcc dtors from __DTOR_LIST__ list under guard
@@ -31,8 +38,13 @@
  *
  * WARNING: Do not change ABI, name or behavior of this function.
  */
+#ifndef _MINGW_DLL_
 void
 __do_global_dtors (void)
+#else
+void __cdecl
+__mingw_dll_do_global_dtors (void)
+#endif
 {
   /* static initialization and incrementation before invocation of dtor
    * ensures that repeated calls to __do_global_dtors() will not invoke
@@ -61,12 +73,27 @@
  *
  * WARNING: Do not change ABI, name or behavior of this function.
  */
+#ifndef _MINGW_DLL_
 void
 __do_global_ctors (void)
+#else
+void __cdecl
+__mingw_dll_do_global_ctors (void)
+#endif
 {
   __SIZE_TYPE__ nptrs = (__SIZE_TYPE__) __CTOR_LIST__[0];
   __SIZE_TYPE__ i;
 
+#ifdef _MINGW_DLL_
+  /* Repeated calls to mingw DLL variant of this function
+   * does not invoke ctors functions multiple times.
+   */
+  static int initialized = 0;
+  if (initialized)
+    return;
+  initialized = 1;
+#endif
+
   if (nptrs == (__SIZE_TYPE__) -1)
     {
       for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++);
@@ -77,9 +104,16 @@
       __CTOR_LIST__[i] ();
     }
 
+  /* mingw DLL variant of this function does not schedule execution of
+   * __do_global_dtors. Instead mingw DLL startup code calls the
+   * __do_global_dtors explicitly.
+   */
+#ifndef _MINGW_DLL_
   atexit (__do_global_dtors);
+#endif
 }
 
+#ifndef _MINGW_DLL_
 /* __main is gcc ABI function which has to be exported.
  * It calls __do_global_ctors function under the guard.
  *
@@ -125,3 +159,4 @@
       __do_global_ctors ();
     }
 }
+#endif
diff --git a/mingw-w64-crt/crt/mingw_dll_ctors_dtors.c b/mingw-w64-crt/crt/mingw_dll_ctors_dtors.c
new file mode 100644
index 0000000..8143c6b
--- /dev/null
+++ b/mingw-w64-crt/crt/mingw_dll_ctors_dtors.c
@@ -0,0 +1,8 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#define _MINGW_DLL_
+#include "gccmain.c"