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 Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public