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