See one inline comment below.
On Wednesday 27 November 2024 18:33:32 Pali Rohár wrote:
> 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
For consistency between __msvcrt_wgetmainargs and __msvcrt_getmainargs
functions, the __msvcrt_wgetmainargs should be declared with "int"
return value too.
I spotted this inconsistency just now.
> +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