crt: test: Add t_noatexit_dll test which verifies that DLL which is not using atexit does not have atexit statically linked

Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/testcases/Makefile.am b/mingw-w64-crt/testcases/Makefile.am
index 88ec065..b4cb67e 100644
--- a/mingw-w64-crt/testcases/Makefile.am
+++ b/mingw-w64-crt/testcases/Makefile.am
@@ -38,6 +38,11 @@
 	$(LINK) -shared -o $@ $^
 t_nontls_dll.exe: libnontls.dll
 
+# Used by t_noatexit_dll
+libnoatexit.dll: libnoatexit.o
+	$(LINK) -shared -o $@ $^
+t_noatexit_dll.exe: libnoatexit.dll
+
 # Used by t_global_ctors
 libglbctors.dll: libglbctors.o
 	$(LINK) -shared -static -o $@ $^ @TARGET_LIBGCC_FILE_NAME@
@@ -128,6 +133,7 @@
   t_mbrlen \
   t_mbrtowc \
   t_mbsrtowcs \
+  t_noatexit_dll \
   t_nontls_dll \
   t_nontls_exe \
   t_tls_dll \
diff --git a/mingw-w64-crt/testcases/libnoatexit.c b/mingw-w64-crt/testcases/libnoatexit.c
new file mode 100644
index 0000000..322d955
--- /dev/null
+++ b/mingw-w64-crt/testcases/libnoatexit.c
@@ -0,0 +1,9 @@
+/* This is simple DLL library which does not use atexit callback */
+
+/* Tentative symbol __mingw_dll_atexit_table_func_ptr is mingw-w64 internal
+ * symbol only for DLL libraries. It is non-NULL if the DLL library is using atexit.
+ */
+int (__cdecl *const __mingw_dll_atexit_table_func_ptr)(int) __attribute__((common)); /* tentative */
+
+__attribute__((dllexport))
+int is_atexit_included(void) { return !!__mingw_dll_atexit_table_func_ptr; }
diff --git a/mingw-w64-crt/testcases/t_noatexit_dll.c b/mingw-w64-crt/testcases/t_noatexit_dll.c
new file mode 100644
index 0000000..e62ad5b
--- /dev/null
+++ b/mingw-w64-crt/testcases/t_noatexit_dll.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+/* mingw-w64 headers */
+#include "libtest.h"
+
+/* This test verifies that DLL library libnoatexit.dll which is not using atexit callbacks, does not have unwanted/unexpected atexit implementation. */
+int main(void)
+{
+  mingw_test_init();
+
+  /* gcc's crtbegin.o (libgcc/config/i386/cygming-crtbegin.c) injects atexit call into every output binary.
+   * So skip this test for all gcc builds (and exclude clang builds for which this test is passing). */
+#if defined(__GNUC__) && !defined(__clang__)
+  printf("test skipped for gcc builds\n");
+  return 77;
+#endif
+
+  HMODULE lib = LoadLibraryA("libnoatexit.dll");
+  if (!lib) {
+    DWORD error = GetLastError();
+    printf("test failed\n");
+    printf("Cannot load DLL library libnoatexit.dll: %lu\n", error);
+    return 1;
+  }
+
+  int (*is_atexit_included)(void) = (int(*)(void))(void(*)(void))GetProcAddress(lib, "is_atexit_included");
+  if (!is_atexit_included) {
+    DWORD error = GetLastError();
+    printf("test failed\n");
+    printf("Cannot resolve is_atexit_included symbol from DLL library libnoatexit.dll: %lu\n", error);
+    return 1;
+  }
+
+  if (is_atexit_included()) {
+    printf("test failed\n");
+    printf("DLL library libnoatexit.dll contains static linked mingw-w64 atexit implementation\n");
+    return 1;
+  } else {
+    printf("test passed\n");
+    printf("DLL library libnoatexit.dll does not contain static linked mingw-w64 atexit implementation\n");
+    return 0;
+  }
+}