[PATCH 0/6] MR9758: Draft: crt: Run MinGW constructors and destructors
(stacked over !9265) @jacek does this look like a good idea? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> --- tools/winebuild/build.h | 1 + tools/winebuild/spec16.c | 1 + tools/winebuild/spec32.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 3acf987aab2..0cabc4648db 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -301,6 +301,7 @@ extern void output_imports( DLLSPEC *spec ); extern void output_import_lib( DLLSPEC *spec, struct strarray files ); extern void output_static_lib( const char *output_name, struct strarray files, int create ); extern void output_exports( DLLSPEC *spec ); +extern void output_crt_sections(void); extern int load_res32_file( const char *name, DLLSPEC *spec ); extern void output_resources( DLLSPEC *spec ); extern void output_bin_resources( DLLSPEC *spec, unsigned int start_rva ); diff --git a/tools/winebuild/spec16.c b/tools/winebuild/spec16.c index face1c551d9..d16e97eabe6 100644 --- a/tools/winebuild/spec16.c +++ b/tools/winebuild/spec16.c @@ -790,6 +790,7 @@ void output_spec16_file( DLLSPEC *spec16 ) output_stubs( spec16 ); output_exports( spec32 ); output_imports( spec16 ); + output_crt_sections(); if (!strcmp( spec16->dll_name, "kernel" )) output_asm_relays16(); if (needs_get_pc_thunk) output_get_pc_thunk(); if (spec16->main_module) diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 7099e82e0f6..ef280b7f51e 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -703,6 +703,32 @@ static void output_load_config(void) } +void output_crt_sections(void) +{ + /* Generate the start/end symbols for .CRT$X?? sections. The start symbol is put into + * .CRT$X?A, the end .CRT$X?Z. Since the linker sort .CRT$X?? sections by name, these symbols + * will end up at the right location.*/ + static const char sections[] = "ict"; + int i; + for (i = 0; sections[i]; i++) + { + char *symbol_name = strmake( "__x%c_a", sections[i] ); + output( "\t.section .CRT$X%cA\n", toupper( sections[i] ) ); + output( "\t.globl %s\n", asm_name( symbol_name ) ); + output( "\t.balign %u\n", get_ptr_size() ); + output( "%s:\n", asm_name( symbol_name ) ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); + + symbol_name = strmake( "__x%c_z", sections[i] ); + output( "\t.section .CRT$X%cZ\n", toupper( sections[i] ) ); + output( "\t.globl %s\n", asm_name( symbol_name ) ); + output( "\t.balign %u\n", get_ptr_size() ); + output( "%s:\n", asm_name( symbol_name ) ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); + } +} + + /******************************************************************* * output_module * @@ -841,6 +867,7 @@ void output_spec32_file( DLLSPEC *spec ) output_imports( spec ); if (needs_get_pc_thunk) output_get_pc_thunk(); output_load_config(); + output_crt_sections(); output_resources( spec ); output_gnu_stack_note(); close_output_file(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> On mingw targets this is already done by ld's linker script. --- tools/winegcc/winegcc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 7458fb08773..724bb9208d5 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -628,6 +628,9 @@ static struct strarray get_link_args( const char *output_name ) strarray_add( &link_args, strmake( "-Wl,-filealign:%s,-align:%s,-driver", file_align, section_align )); + /* Merge .CRT sections into .rdata */ + strarray_add( &link_args, "-Wl,-merge:.CRT=.rdata" ); + strarray_addall( &link_args, flags ); return link_args; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> --- dlls/msvcr100/Makefile.in | 1 + dlls/msvcr110/Makefile.in | 1 + dlls/msvcr120/Makefile.in | 1 + dlls/msvcr70/Makefile.in | 1 + dlls/msvcr71/Makefile.in | 1 + dlls/msvcr80/Makefile.in | 1 + dlls/msvcr90/Makefile.in | 1 + dlls/msvcrt/Makefile.in | 1 + dlls/msvcrt/crt_init.c | 51 +++++++++++++++++++++++++++++++++++++ dlls/msvcrt/crt_main.c | 2 ++ dlls/msvcrt/crt_wmain.c | 2 ++ dlls/ucrtbase/Makefile.in | 1 + dlls/winecrt0/crt_dllmain.c | 50 +++++++++++++++++++++++++++++++++++- 13 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 dlls/msvcrt/crt_init.c diff --git a/dlls/msvcr100/Makefile.in b/dlls/msvcr100/Makefile.in index a0a3f64d6bf..34182e69f19 100644 --- a/dlls/msvcr100/Makefile.in +++ b/dlls/msvcr100/Makefile.in @@ -10,6 +10,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr110/Makefile.in b/dlls/msvcr110/Makefile.in index e6798427795..fdbcba054d4 100644 --- a/dlls/msvcr110/Makefile.in +++ b/dlls/msvcr110/Makefile.in @@ -10,6 +10,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr120/Makefile.in b/dlls/msvcr120/Makefile.in index b233753fa2e..3465d77a31e 100644 --- a/dlls/msvcr120/Makefile.in +++ b/dlls/msvcr120/Makefile.in @@ -10,6 +10,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr70/Makefile.in b/dlls/msvcr70/Makefile.in index 9413738ae1f..be93d88764b 100644 --- a/dlls/msvcr70/Makefile.in +++ b/dlls/msvcr70/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr71/Makefile.in b/dlls/msvcr71/Makefile.in index 6e0b855cac3..c59ce97e8e4 100644 --- a/dlls/msvcr71/Makefile.in +++ b/dlls/msvcr71/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr80/Makefile.in b/dlls/msvcr80/Makefile.in index 2a84383f79d..78accf161e9 100644 --- a/dlls/msvcr80/Makefile.in +++ b/dlls/msvcr80/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcr90/Makefile.in b/dlls/msvcr90/Makefile.in index d476d2e3080..3dfc080e554 100644 --- a/dlls/msvcr90/Makefile.in +++ b/dlls/msvcr90/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcrt/Makefile.in b/dlls/msvcrt/Makefile.in index aa068b62e51..a4023568d71 100644 --- a/dlls/msvcrt/Makefile.in +++ b/dlls/msvcrt/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/msvcrt/crt_init.c b/dlls/msvcrt/crt_init.c new file mode 100644 index 00000000000..5dc64c5882b --- /dev/null +++ b/dlls/msvcrt/crt_init.c @@ -0,0 +1,51 @@ +/* Utility functions for calling MSVC/MingW ctors & dtors from mainCRTStartup. */ + +#if 0 +#pragma makedep implib +#endif + +#include <process.h> +#include <stdlib.h> +#include "minwindef.h" + +extern _PIFV __xi_a[]; +extern _PIFV __xi_z[]; +extern _PVFV __xc_a[]; +extern _PVFV __xc_z[]; +extern _PVFV __xt_a[]; +extern _PVFV __xt_z[]; + +static inline int INIT_initterm_e(_PIFV *table, _PIFV *end) +{ +#if _MSVCR_VER<80 + int res = 0; + + while (!res && table < end) { + if (*table) + res = (**table)(); + table++; + } + return res; +#else + return _initterm_e(table, end); +#endif +} + +void CDECL _initterm(_PVFV *,_PVFV *); + +static __cdecl void do_global_dtors(void) +{ + _initterm(__xt_a, __xt_z); +} + +void do_global_ctors(void) +{ + if (INIT_initterm_e(__xi_a, __xi_z) != 0) return; + _initterm(__xc_a, __xc_z); + +#ifdef _UCRT + _crt_atexit(do_global_dtors); +#else + _onexit((_onexit_t)do_global_dtors); +#endif +} diff --git a/dlls/msvcrt/crt_main.c b/dlls/msvcrt/crt_main.c index eb785e30bb0..5eb9e5032a0 100644 --- a/dlls/msvcrt/crt_main.c +++ b/dlls/msvcrt/crt_main.c @@ -31,6 +31,7 @@ #include "winternl.h" int __cdecl main(int argc, char **argv, char **env); +void do_global_ctors( void ); static const IMAGE_NT_HEADERS *get_nt_header( void ) { @@ -54,6 +55,7 @@ int __cdecl mainCRTStartup(void) __getmainargs(&argc, &argv, &env, 0, &new_mode); #endif _set_app_type(get_nt_header()->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? _crt_gui_app : _crt_console_app); + do_global_ctors(); ret = main(argc, argv, env); diff --git a/dlls/msvcrt/crt_wmain.c b/dlls/msvcrt/crt_wmain.c index 79755d1a6e9..71cc0e48ec7 100644 --- a/dlls/msvcrt/crt_wmain.c +++ b/dlls/msvcrt/crt_wmain.c @@ -31,6 +31,7 @@ #include "winternl.h" int __cdecl wmain(int argc, WCHAR **argv, WCHAR **env); +void do_global_ctors(void); static const IMAGE_NT_HEADERS *get_nt_header( void ) { @@ -54,6 +55,7 @@ int __cdecl wmainCRTStartup(void) __wgetmainargs(&argc, &argv, &env, 0, &new_mode); #endif _set_app_type(get_nt_header()->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? _crt_gui_app : _crt_console_app); + do_global_ctors(); ret = wmain(argc, argv, env); diff --git a/dlls/ucrtbase/Makefile.in b/dlls/ucrtbase/Makefile.in index a3bb54750af..1bd1073dcf1 100644 --- a/dlls/ucrtbase/Makefile.in +++ b/dlls/ucrtbase/Makefile.in @@ -9,6 +9,7 @@ SOURCES = \ console.c \ cpp.c \ crt_gccmain.c \ + crt_init.c \ crt_main.c \ crt_winmain.c \ crt_wmain.c \ diff --git a/dlls/winecrt0/crt_dllmain.c b/dlls/winecrt0/crt_dllmain.c index 181760c884a..0b27189b98c 100644 --- a/dlls/winecrt0/crt_dllmain.c +++ b/dlls/winecrt0/crt_dllmain.c @@ -22,12 +22,60 @@ #include <stdarg.h> #include <stdio.h> +#include <process.h> #include "windef.h" #include "winbase.h" +extern _PIFV __xi_a[]; +extern _PIFV __xi_z[]; +extern _PVFV __xc_a[]; +extern _PVFV __xc_z[]; +extern _PVFV __xt_a[]; +extern _PVFV __xt_z[]; + +static inline void initterm( _PVFV *start,_PVFV *end ) +{ + _PVFV* current = start; + + while (current<end) + { + if (*current) + (**current)(); + current++; + } +} + +static inline int initterm_e( _PIFV *table, _PIFV *end ) +{ + int res = 0; + + while (!res && table < end) { + if (*table) + res = (**table)(); + table++; + } + return res; +} + +static void do_global_ctors(void) +{ + if (initterm_e( __xi_a, __xi_z ) != 0) return; + initterm( __xc_a, __xc_z ); +} + + +static void do_global_dtors(void) +{ + initterm( __xt_a, __xt_z ); +} + BOOL WINAPI DllMainCRTStartup( HINSTANCE inst, DWORD reason, void *reserved ) { - return DllMain( inst, reason, reserved ); + BOOL ret; + if (reason == DLL_PROCESS_ATTACH) do_global_ctors(); + ret = DllMain( inst, reason, reserved ); + if (reason == DLL_PROCESS_DETACH) do_global_dtors(); + return ret; } #endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> This creates placeholders in case our runtime library is being linked on MSVC targets, which doesn't create __CTOR_LIST__ and __DTOR_LIST__ symbols. --- tools/winebuild/spec32.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index ef280b7f51e..b0e68b9ab99 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -726,6 +726,21 @@ void output_crt_sections(void) output( "%s:\n", asm_name( symbol_name ) ); output( "\t%s 0\n", get_asm_ptr_keyword() ); } + + /* When linking on MinGW targets, the linker script creates a __CTOR_LIST__ and a __DTOR_LIST__ + * symbol for constructor and destructor sections; but MSVC targets don't. To ensure our + * runtime library is usable in either cases, we generate a dummy symbol here, and emit a + * -alternatename flag in winegcc on MSVC targets, creating aliases from __CTOR_LIST__/ + * __DTOR_LIST__ to this dummy symbol, so everything works. + * + * If someone builds on mingw but links on windows, all constructors and destructors will be + * lost. That's user error. */ + output( "\t.section .rdata\n" ); + output( "\t.globl __wine_spec_dummy_ctor_dtor_list__\n" ); + output( "\t.balign %u\n", get_ptr_size() ); + output( "__wine_spec_dummy_ctor_dtor_list__:\n" ); + output( "\t%s -1\n", get_asm_ptr_keyword() ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> --- tools/winegcc/winegcc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 724bb9208d5..74f428946c5 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -631,6 +631,11 @@ static struct strarray get_link_args( const char *output_name ) /* Merge .CRT sections into .rdata */ strarray_add( &link_args, "-Wl,-merge:.CRT=.rdata" ); + strarray_add( &link_args, "-Wl,-alternatename:__CTOR_LIST__=__wine_spec_dummy_ctor_dtor_list__" ); + strarray_add( &link_args, "-Wl,-alternatename:__DTOR_LIST__=__wine_spec_dummy_ctor_dtor_list__" ); + strarray_add( &link_args, "-Wl,-alternatename:___CTOR_LIST__=__wine_spec_dummy_ctor_dtor_list__" ); + strarray_add( &link_args, "-Wl,-alternatename:___DTOR_LIST__=__wine_spec_dummy_ctor_dtor_list__" ); + strarray_addall( &link_args, flags ); return link_args; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
From: Yuxuan Shui <yshui@codeweavers.com> --- dlls/msvcrt/crt_init.c | 12 ++++++++++++ dlls/winecrt0/crt_dllmain.c | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/dlls/msvcrt/crt_init.c b/dlls/msvcrt/crt_init.c index 5dc64c5882b..387b8ee9b23 100644 --- a/dlls/msvcrt/crt_init.c +++ b/dlls/msvcrt/crt_init.c @@ -8,6 +8,11 @@ #include <stdlib.h> #include "minwindef.h" +/* Reference: mingw-w64-crt: crt/gccmain.c */ +typedef void (*fnptr)(void); +extern fnptr __CTOR_LIST__[]; +extern fnptr __DTOR_LIST__[]; + extern _PIFV __xi_a[]; extern _PIFV __xi_z[]; extern _PVFV __xc_a[]; @@ -35,11 +40,18 @@ void CDECL _initterm(_PVFV *,_PVFV *); static __cdecl void do_global_dtors(void) { + SIZE_T i; + for (i = 1; __DTOR_LIST__[i]; i++) __DTOR_LIST__[i](); _initterm(__xt_a, __xt_z); } void do_global_ctors(void) { + ULONG_PTR nfns = (ULONG_PTR)__CTOR_LIST__[0], i; + if (nfns == (ULONG_PTR)-1) + for (nfns = 0; __CTOR_LIST__[nfns + 1]; nfns++); + for (i = nfns; i >= 1; i--) __CTOR_LIST__[i](); + if (INIT_initterm_e(__xi_a, __xi_z) != 0) return; _initterm(__xc_a, __xc_z); diff --git a/dlls/winecrt0/crt_dllmain.c b/dlls/winecrt0/crt_dllmain.c index 0b27189b98c..7b3fcc8d419 100644 --- a/dlls/winecrt0/crt_dllmain.c +++ b/dlls/winecrt0/crt_dllmain.c @@ -26,6 +26,11 @@ #include "windef.h" #include "winbase.h" +/* Reference: mingw-w64-crt: crt/gccmain.c */ +typedef void (*fnptr)(void); +extern fnptr __CTOR_LIST__[]; +extern fnptr __DTOR_LIST__[]; + extern _PIFV __xi_a[]; extern _PIFV __xi_z[]; extern _PVFV __xc_a[]; @@ -59,6 +64,10 @@ static inline int initterm_e( _PIFV *table, _PIFV *end ) static void do_global_ctors(void) { + ULONG_PTR nfns = (ULONG_PTR)__CTOR_LIST__[0], i; + if (nfns == (ULONG_PTR)-1) + for (nfns = 0; __CTOR_LIST__[nfns + 1]; nfns++); + for (i = nfns; i >= 1; i--) __CTOR_LIST__[i](); if (initterm_e( __xi_a, __xi_z ) != 0) return; initterm( __xc_a, __xc_z ); } @@ -66,6 +75,8 @@ static void do_global_ctors(void) static void do_global_dtors(void) { + SIZE_T i; + for (i = 1; __DTOR_LIST__[i]; i++) __DTOR_LIST__[i](); initterm( __xt_a, __xt_z ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9758
participants (2)
-
Yuxuan Shui -
Yuxuan Shui (@yshui)