Visual C++ CRT DLL libraries older than VC70 / msvcr70.dll have different
ABI of __getmainargs() and __wgetmainargs() functions. Their return value
is void, instead of int. This includes VC++ libs crtdll.dll, msvcrt10.dll,
msvcrt20.dll, msvcrt40.dll, msvcr40d.dll, msvcrt.dll and msvcrtd.dll.

Same applies for OS system msvcrt.dll library for older systems than
Windows XP.

System version of msvcrt.dll library since Windows XP has same ABI of
__getmainargs() and __wgetmainargs() functions as Visal C++ msvcr70.dll
library.

MinGW-w64 already provides declaration of __getmainargs() and
__wgetmainargs() with int return value. So it is expected that these
functions in MinGW-w64 perspective returns int and let caller to handle
errors.

Import libraries for crtdll.dll, msvcrt10.dll and msvcrt20.dll have already
wrappers around __getmainargs() and __wgetmainargs() which handle this kind
of ABI incompatibility.

Add a new wrappers around __getmainargs() and __wgetmainargs() also for
msvcrt40.dll, msvcr40d.dll and msvcrtd.dll import libraries to correctly
return integer value 0.

For msvcrt.dll library is situation quite complicated as its ABI is not
stable and was changed in Windows XP version. But the problem is only with
i386 version as all AMD64 and ARM systems were released after Windows XP.

As int return value on i386 is stored in the eax register we can call this
function from C even with wrong return value in declaration and ignoring it
return value. This function does not touch argc/argv/envp arguments on
error, so we can use this fact to detect failure independently of return
value ABI. With this trick is it possible to achieve i386 implementation of
MinGW-w64 wrappers around __getmainargs() and __wgetmainargs() which would
work with both Visual C++ ABI and also with Window XP ABI.
---
 mingw-w64-crt/Makefile.am                   | 10 +++++--
 mingw-w64-crt/lib-common/msvcrt.def.in      |  6 ++--
 mingw-w64-crt/lib32/msvcr40d.def.in         |  4 +--
 mingw-w64-crt/lib32/msvcrt40.def.in         |  4 +--
 mingw-w64-crt/lib32/msvcrtd.def.in          |  4 +--
 mingw-w64-crt/misc/crtdll__getmainargs.c    |  4 +++
 mingw-w64-crt/misc/msvcrt20__getmainargs.c  |  4 +++
 mingw-w64-crt/misc/msvcrt20__wgetmainargs.c |  4 +++
 mingw-w64-crt/misc/msvcrt40__getmainargs.c  | 19 ++++++++++++
 mingw-w64-crt/misc/msvcrt40__wgetmainargs.c | 19 ++++++++++++
 mingw-w64-crt/misc/msvcrt__getmainargs.c    | 32 +++++++++++++++++++++
 mingw-w64-crt/misc/msvcrt__wgetmainargs.c   | 32 +++++++++++++++++++++
 12 files changed, 132 insertions(+), 10 deletions(-)
 create mode 100644 mingw-w64-crt/misc/msvcrt40__getmainargs.c
 create mode 100644 mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
 create mode 100644 mingw-w64-crt/misc/msvcrt__getmainargs.c
 create mode 100644 mingw-w64-crt/misc/msvcrt__wgetmainargs.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 22bb117a0faf..b41411bb9797 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -463,6 +463,8 @@ src_ucrtbasearm64=\
 src_msvcrt32=\
   $(src_msvcrt) \
   $(src_msvcrt_add_x86) \
+  misc/msvcrt__getmainargs.c \
+  misc/msvcrt__wgetmainargs.c \
   math/i386__copysignf.c \
   misc/___mb_cur_max_func.c \
   misc/__p__osplatform.c \
@@ -822,14 +824,18 @@ src_msvcrt40=\
   $(src_pre_msvcr71) \
   $(src_pre_msvcr80) \
   $(src_pre_msvcr100) \
-  $(src_pre_msvcr120)
+  $(src_pre_msvcr120) \
+  misc/msvcrt40__getmainargs.c \
+  misc/msvcrt40__wgetmainargs.c
 
 src_msvcrtd=\
   $(src_pre_msvcr70) \
   $(src_pre_msvcr71) \
   $(src_pre_msvcr80) \
   $(src_pre_msvcr100) \
-  $(src_pre_msvcr120)
+  $(src_pre_msvcr120) \
+  misc/msvcrt40__getmainargs.c \
+  misc/msvcrt40__wgetmainargs.c
 
 src_msvcr70=\
   $(src_pre_msvcr71) \
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in 
b/mingw-w64-crt/lib-common/msvcrt.def.in
index feeeb1c35552..945ce61408f5 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -459,7 +459,8 @@ __crtLCMapStringA
 __dllonexit
 __doserrno
 __fpecode
-__getmainargs
+F_I386(__msvcrt_getmainargs == __getmainargs) ; pre-XP i386 msvcrt.dll's 
__getmainargs is incompatible with mingw-w64's __getmainargs, real 
__getmainargs provided by emu
+F_NON_I386(__getmainargs)
 F_X86_ANY(__initenv DATA) ; arm32 and arm64 __initenv provided by emu
 __isascii
 __iscsym
@@ -507,7 +508,8 @@ __toascii
 __unDName
 F_X86_ANY(__unguarded_readlc_active DATA)
 __wargv DATA
-__wgetmainargs
+F_I386(__msvcrt_wgetmainargs == __wgetmainargs) ; pre-XP i386 msvcrt.dll's 
__wgetmainargs is incompatible with mingw-w64's __wgetmainargs, real 
__wgetmainargs provided by emu
+F_NON_I386(__wgetmainargs)
 F_X86_ANY(__winitenv DATA) ; arm32 and arm64 __winitenv provided by emu
 F_I386(_abnormal_termination)
 _access
diff --git a/mingw-w64-crt/lib32/msvcr40d.def.in 
b/mingw-w64-crt/lib32/msvcr40d.def.in
index 9a108cb06a6f..590400770339 100644
--- a/mingw-w64-crt/lib32/msvcr40d.def.in
+++ b/mingw-w64-crt/lib32/msvcr40d.def.in
@@ -1022,7 +1022,7 @@ __STRINGTOLD
 __dllonexit
 __doserrno
 __fpecode
-__getmainargs
+__msvcrt40_getmainargs == __getmainargs ; msvcr40d.dll's __getmainargs is 
incompatible with mingw-w64's __getmainargs, real __getmainargs provided by emu
 __isascii
 __iscsym
 __iscsymf
@@ -1063,7 +1063,7 @@ __threadhandle
 __threadid
 __toascii
 __unDName
-__wgetmainargs
+__msvcrt40_wgetmainargs == __wgetmainargs ; msvcr40d.dll's __wgetmainargs is 
incompatible with mingw-w64's __wgetmainargs, real __wgetmainargs provided by 
emu
 _abnormal_termination
 _access
 _adj_fdiv_m16i ; msvc symbol is without decoration but callee pop stack (like 
stdcall @4)
diff --git a/mingw-w64-crt/lib32/msvcrt40.def.in 
b/mingw-w64-crt/lib32/msvcrt40.def.in
index 88ae2bd2399f..80541502a0b6 100644
--- a/mingw-w64-crt/lib32/msvcrt40.def.in
+++ b/mingw-w64-crt/lib32/msvcrt40.def.in
@@ -999,7 +999,7 @@ __STRINGTOLD
 __dllonexit
 __doserrno
 __fpecode
-__getmainargs
+__msvcrt40_getmainargs == __getmainargs ; msvcrt40.dll's __getmainargs is 
incompatible with mingw-w64's __getmainargs, real __getmainargs provided by emu
 __isascii
 __iscsym
 __iscsymf
@@ -1037,7 +1037,7 @@ __threadhandle
 __threadid
 __toascii
 __unDName
-__wgetmainargs
+__msvcrt40_wgetmainargs == __wgetmainargs ; msvcrt40.dll's __wgetmainargs is 
incompatible with mingw-w64's __wgetmainargs, real __wgetmainargs provided by 
emu
 _abnormal_termination
 _access
 _adj_fdiv_m16i ; msvc symbol is without decoration but callee pop stack (like 
stdcall @4)
diff --git a/mingw-w64-crt/lib32/msvcrtd.def.in 
b/mingw-w64-crt/lib32/msvcrtd.def.in
index 4313c797a179..976374a29c3a 100644
--- a/mingw-w64-crt/lib32/msvcrtd.def.in
+++ b/mingw-w64-crt/lib32/msvcrtd.def.in
@@ -165,7 +165,7 @@ __crtLCMapStringA
 __dllonexit
 __doserrno
 __fpecode
-__getmainargs
+__msvcrt40_getmainargs == __getmainargs ; msvcrtd.dll's __getmainargs has same 
API as msvcrt40.dll's __getmainargs, real __getmainargs provided by emu
 __initenv DATA
 __isascii
 __iscsym
@@ -216,7 +216,7 @@ __toascii
 __unDName
 __unguarded_readlc_active DATA
 __wargv DATA
-__wgetmainargs
+__msvcrt40_wgetmainargs == __wgetmainargs ; msvcrtd.dll's __wgetmainargs has 
same API as msvcrt40.dll's __wgetmainargs, real __wgetmainargs provided by emu
 __winitenv DATA
 _abnormal_termination
 _access
diff --git a/mingw-w64-crt/misc/crtdll__getmainargs.c 
b/mingw-w64-crt/misc/crtdll__getmainargs.c
index 81e37aa5555d..61401ca3f81a 100644
--- a/mingw-w64-crt/misc/crtdll__getmainargs.c
+++ b/mingw-w64-crt/misc/crtdll__getmainargs.c
@@ -10,6 +10,10 @@
 _CRTIMP void __cdecl __GetMainArgs(int *argc, char ***argv, char ***envp, int 
expand_wildcards);
 int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
expand_wildcards, __UNUSED_PARAM(_startupinfo *startup_info))
 {
+  /*
+   * crtdll.dll's __GetMainArgs() function terminates process on error.
+   * If it returns back to the caller then it means that it succeeded.
+   */
   __GetMainArgs(argc, argv, envp, expand_wildcards);
   return 0;
 }
diff --git a/mingw-w64-crt/misc/msvcrt20__getmainargs.c 
b/mingw-w64-crt/misc/msvcrt20__getmainargs.c
index 3162a20ab359..7a119297d646 100644
--- a/mingw-w64-crt/misc/msvcrt20__getmainargs.c
+++ b/mingw-w64-crt/misc/msvcrt20__getmainargs.c
@@ -10,6 +10,10 @@
 _CRTIMP void __cdecl __msvcrt20_getmainargs(int *argc, char ***argv, char 
***envp, int expand_wildcards, int newmode);
 int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
expand_wildcards, _startupinfo *startup_info)
 {
+  /*
+   * msvcrt20.dll's __getmainargs() function terminates process on error.
+   * If it returns back to the caller then it means that it succeeded.
+   */
   __msvcrt20_getmainargs(argc, argv, envp, expand_wildcards, 
startup_info->newmode);
   return 0;
 }
diff --git a/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c 
b/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
index c8338bb0aca0..7a8207295f81 100644
--- a/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
+++ b/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
@@ -10,6 +10,10 @@
 _CRTIMP void __cdecl __msvcrt20_wgetmainargs(int *argc, wchar_t ***argv, 
wchar_t ***envp, int expand_wildcards, int newmode);
 int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
expand_wildcards, _startupinfo *startup_info)
 {
+  /*
+   * msvcrt20.dll's __wgetmainargs() function terminates process on error.
+   * If it returns back to the caller then it means that it succeeded.
+   */
   __msvcrt20_wgetmainargs(argc, argv, envp, expand_wildcards, 
startup_info->newmode);
   return 0;
 }
diff --git a/mingw-w64-crt/misc/msvcrt40__getmainargs.c 
b/mingw-w64-crt/misc/msvcrt40__getmainargs.c
new file mode 100644
index 000000000000..541db331c6ed
--- /dev/null
+++ b/mingw-w64-crt/misc/msvcrt40__getmainargs.c
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+#include <internal.h>
+
+/* Define __getmainargs() function via msvcrt40.dll __getmainargs() function */
+_CRTIMP void __cdecl __msvcrt40_getmainargs(int *argc, char ***argv, char 
***envp, int expand_wildcards, _startupinfo *startup_info);
+int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
expand_wildcards, _startupinfo *startup_info)
+{
+  /*
+   * msvcrt40.dll's __getmainargs() function terminates process on error.
+   * If it returns back to the caller then it means that it succeeded.
+   */
+  __msvcrt40_getmainargs(argc, argv, envp, expand_wildcards, startup_info);
+  return 0;
+}
diff --git a/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c 
b/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
new file mode 100644
index 000000000000..631b87b03fa8
--- /dev/null
+++ b/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+#include <internal.h>
+
+/* Define __wgetmainargs() function via msvcrt40.dll __wgetmainargs() function 
*/
+_CRTIMP void __cdecl __msvcrt40_wgetmainargs(int *argc, wchar_t ***argv, 
wchar_t ***envp, int expand_wildcards, _startupinfo *startup_info);
+int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
expand_wildcards, _startupinfo *startup_info)
+{
+  /*
+   * msvcrt40.dll's __wgetmainargs() function terminates process on error.
+   * If it returns back to the caller then it means that it succeeded.
+   */
+  __msvcrt40_wgetmainargs(argc, argv, envp, expand_wildcards, startup_info);
+  return 0;
+}
diff --git a/mingw-w64-crt/misc/msvcrt__getmainargs.c 
b/mingw-w64-crt/misc/msvcrt__getmainargs.c
new file mode 100644
index 000000000000..95c301f1fa54
--- /dev/null
+++ b/mingw-w64-crt/misc/msvcrt__getmainargs.c
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+#include <internal.h>
+
+/* Define __getmainargs() function via msvcrt.dll __getmainargs() function */
+_CRTIMP int __cdecl __msvcrt_getmainargs(int *argc, char ***argv, char 
***envp, int expand_wildcards, _startupinfo *startup_info);
+int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
expand_wildcards, _startupinfo *startup_info)
+{
+  /*
+   * ABI of msvcrt.dll __getmainargs() function was changed in Windows XP.
+   * In Windows 2000 and older versions of msvcrt.dll, including the original
+   * Visual C++ 6.0 msvcrt.dll version, __getmainargs() has void return value
+   * and it terminate process on failure. Since Windows XP this function has
+   * int return value and returns -1 on failure. It is up to the caller to
+   * terminate process. As int return value on i386 is stored in the eax
+   * register we can call this function from C even with wrong return value in
+   * declaration and ignoring it return value. This function does not touch
+   * argc/argv/envp arguments on error, so we can use this fact to detect
+   * failure independently of return value ABI.
+   */
+  *argc = -1;
+  *argv = NULL;
+  *envp = NULL;
+  (void)__msvcrt_getmainargs(argc, argv, envp, expand_wildcards, startup_info);
+  if (*argc == -1 || *argv == NULL || *envp == NULL)
+    return -1;
+  return 0;
+}
diff --git a/mingw-w64-crt/misc/msvcrt__wgetmainargs.c 
b/mingw-w64-crt/misc/msvcrt__wgetmainargs.c
new file mode 100644
index 000000000000..35e9d596f933
--- /dev/null
+++ b/mingw-w64-crt/misc/msvcrt__wgetmainargs.c
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+#include <internal.h>
+
+/* Define __wgetmainargs() function via msvcrt.dll __wgetmainargs() function */
+_CRTIMP void __cdecl __msvcrt_wgetmainargs(int *argc, wchar_t ***argv, wchar_t 
***envp, int expand_wildcards, _startupinfo *startup_info);
+int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
expand_wildcards, _startupinfo *startup_info)
+{
+  /*
+   * ABI of msvcrt.dll __wgetmainargs() function was changed in Windows XP.
+   * In Windows 2000 and older versions of msvcrt.dll, including the original
+   * Visual C++ 6.0 msvcrt.dll version, __wgetmainargs() has void return value
+   * and it terminate process on failure. Since Windows XP this function has
+   * int return value and returns -1 on failure. It is up to the caller to
+   * terminate process. As int return value on i386 is stored in the eax
+   * register we can call this function from C even with wrong return value in
+   * declaration and ignoring it return value. This function does not touch
+   * argc/argv/envp arguments on error, so we can use this fact to detect
+   * failure independently of return value ABI.
+   */
+  *argc = -1;
+  *argv = NULL;
+  *envp = NULL;
+  (void)__msvcrt_wgetmainargs(argc, argv, envp, expand_wildcards, 
startup_info);
+  if (*argc == -1 || *argv == NULL || *envp == NULL)
+    return -1;
+  return 0;
+}
-- 
2.20.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to