From 36048242624c873e0bc752a15a5bd116fcf4c93c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 8 Jan 2004 03:36:53 +0000 Subject: [PATCH] If supported by the linker, prevent the ELF loader from calling the dll constructors at load time and call them from the dll entry point instead. --- configure | 66 +++++++++++++++ configure.ac | 9 +++ dlls/kernel/process.c | 3 + dlls/ntdll/loader.c | 2 + include/config.h.in | 5 ++ tools/winebuild/spec32.c | 168 ++++++++++++++++----------------------- 6 files changed, 155 insertions(+), 98 deletions(-) diff --git a/configure b/configure index b95800e0190..7ad9bc268b0 100755 --- a/configure +++ b/configure @@ -13649,6 +13649,72 @@ echo "${ECHO_T}$ac_cv_c_dll_zdefs" >&6 LDDLL="$LDDLL,-z,defs" fi + echo "$as_me:$LINENO: checking whether the linker accepts -init and -fini" >&5 +echo $ECHO_N "checking whether the linker accepts -init and -fini... $ECHO_C" >&6 +if test "${ac_cv_c_dll_init_fini+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_wine_try_cflags_saved=$CFLAGS +CFLAGS="$CFLAGS -fPIC -shared -Wl,-Bsymbolic,-init,__wine_spec_init,-fini,__wine_spec_fini" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_dll_init_fini="yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_dll_init_fini="no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +fi +echo "$as_me:$LINENO: result: $ac_cv_c_dll_init_fini" >&5 +echo "${ECHO_T}$ac_cv_c_dll_init_fini" >&6 + if test "$ac_cv_c_dll_init_fini" = "yes" + then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LINKER_INIT_FINI 1 +_ACEOF + + LDDLL="$LDDLL,-init,__wine_spec_init,-fini,__wine_spec_fini" + fi + echo "$as_me:$LINENO: checking whether the linker accepts --export-dynamic" >&5 echo $ECHO_N "checking whether the linker accepts --export-dynamic... $ECHO_C" >&6 if test "${ac_cv_c_export_dynamic+set}" = set; then diff --git a/configure.ac b/configure.ac index 161211eb8c3..5ea663f7972 100644 --- a/configure.ac +++ b/configure.ac @@ -880,6 +880,15 @@ case $host_os in LDDLL="$LDDLL,-z,defs" fi + AC_CACHE_CHECK([whether the linker accepts -init and -fini], ac_cv_c_dll_init_fini, + [WINE_TRY_CFLAGS([-fPIC -shared -Wl,-Bsymbolic,-init,__wine_spec_init,-fini,__wine_spec_fini], + ac_cv_c_dll_init_fini="yes",ac_cv_c_dll_init_fini="no")]) + if test "$ac_cv_c_dll_init_fini" = "yes" + then + AC_DEFINE(HAVE_LINKER_INIT_FINI,1,[Define if the linker supports renaming the init and fini functions]) + LDDLL="$LDDLL,-init,__wine_spec_init,-fini,__wine_spec_fini" + fi + AC_CACHE_CHECK([whether the linker accepts --export-dynamic], ac_cv_c_export_dynamic, [WINE_TRY_CFLAGS([-fPIC -Wl,--export-dynamic], ac_cv_c_export_dynamic="yes",ac_cv_c_export_dynamic="no")]) diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c index 20111626f20..da84b88115d 100644 --- a/dlls/kernel/process.c +++ b/dlls/kernel/process.c @@ -618,9 +618,12 @@ static BOOL process_init( char *argv[], char **environ ) RTL_USER_PROCESS_PARAMETERS *params; PEB *peb = NtCurrentTeb()->Peb; HANDLE hstdin, hstdout, hstderr; + extern void __wine_dbg_kernel32_init(void); PTHREAD_Init(); + __wine_dbg_kernel32_init(); /* hack: register debug channels early */ + setbuf(stdout,NULL); setbuf(stderr,NULL); setlocale(LC_CTYPE,""); diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index e3afb101c03..94fb6811a5e 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1956,8 +1956,10 @@ void __wine_process_init( int argc, char *argv[] ) NTSTATUS status; ANSI_STRING func_name; void (* DECLSPEC_NORETURN init_func)(); + extern void __wine_dbg_ntdll_init(void); thread_init(); + __wine_dbg_ntdll_init(); /* hack: register debug channels early */ /* setup the load callback and create ntdll modref */ wine_dll_set_callback( load_builtin_callback ); diff --git a/include/config.h.in b/include/config.h.in index be8b724aebd..1ce5de78b50 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -461,6 +461,11 @@ */ #undef HAVE_LIBXXSHM +/* + Define if the linker supports renaming the init + and fini functions */ +#undef HAVE_LINKER_INIT_FINI + /* Define to 1 if you have the header file. */ diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 02567c3a99e..dc19d00d43e 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -491,7 +491,6 @@ void BuildSpec32File( FILE *outfile ) int nr_exports, nr_imports, nr_resources; int characteristics, subsystem; DWORD page_size; - char constructor[100]; #ifdef HAVE_GETPAGESIZE page_size = getpagesize(); @@ -569,30 +568,53 @@ void BuildSpec32File( FILE *outfile ) nr_resources = output_resources( outfile ); - /* Output LibMain function */ + /* Output the entry point function */ + + fprintf( outfile, "extern int __wine_main_argc;\n" ); + fprintf( outfile, "extern char **__wine_main_argv;\n" ); + fprintf( outfile, "extern char **__wine_main_environ;\n" ); + fprintf( outfile, "extern unsigned short **__wine_main_wargv;\n" ); + fprintf( outfile, "extern void _init(int, char**, char**);\n" ); + fprintf( outfile, "extern void _fini();\n" ); characteristics = subsystem = 0; switch(SpecMode) { case SPEC_MODE_DLL: - if (init_func) fprintf( outfile, "extern void %s();\n", init_func ); + if (init_func) + fprintf( outfile, "extern int __stdcall %s( void*, unsigned int, void* );\n\n", init_func ); else { fprintf( outfile, "#ifdef __GNUC__\n" ); fprintf( outfile, "# ifdef __APPLE__\n" ); - fprintf( outfile, "extern void DllMain() __attribute__((weak_import));\n" ); + fprintf( outfile, "extern int __stdcall DllMain( void*, unsigned int, void* ) __attribute__((weak_import));\n" ); fprintf( outfile, "# else\n" ); - fprintf( outfile, "extern void DllMain() __attribute__((weak));\n" ); + fprintf( outfile, "extern int __stdcall DllMain( void*, unsigned int, void* ) __attribute__((weak));\n" ); fprintf( outfile, "# endif\n" ); fprintf( outfile, "#else\n" ); - fprintf( outfile, "extern void DllMain();\n" ); + fprintf( outfile, "extern int __stdcall DllMain( void*, unsigned int, void* );\n" ); fprintf( outfile, "static void __asm__dummy_dllmain(void)" ); fprintf( outfile, " { asm(\".weak " __ASM_NAME("DllMain") "\"); }\n" ); - fprintf( outfile, "#endif\n" ); + fprintf( outfile, "#endif\n\n" ); + init_func = "DllMain"; } +#ifdef HAVE_LINKER_INIT_FINI + fprintf( outfile, + "static int __stdcall __wine_dll_main( void *inst, unsigned int reason, void *reserved )\n" + "{\n" + " int ret;\n" + " if (reason == %d) _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" + " ret = %s ? %s( inst, reason, reserved ) : 1;\n" + " if (reason == %d) _fini();\n" + " return ret;\n" + "}\n", + DLL_PROCESS_ATTACH, init_func, init_func, DLL_PROCESS_DETACH ); + init_func = "__wine_dll_main"; +#endif characteristics = IMAGE_FILE_DLL; break; case SPEC_MODE_GUIEXE: + case SPEC_MODE_GUIEXE_UNICODE: if (!init_func) init_func = "WinMain"; fprintf( outfile, "\ntypedef struct {\n" @@ -604,8 +626,6 @@ void BuildSpec32File( FILE *outfile ) " char *lpReserved2;\n" " void *hStdInput, *hStdOutput, *hStdError;\n" "} STARTUPINFOA;\n" - "int _ARGC;\n" - "char **_ARGV;\n" "extern int __stdcall %s(void *,void *,char *,int);\n" "extern char * __stdcall GetCommandLineA(void);\n" "extern void * __stdcall GetModuleHandleA(char *);\n" @@ -613,11 +633,9 @@ void BuildSpec32File( FILE *outfile ) "extern void __stdcall ExitProcess(unsigned int);\n" "static void __wine_exe_main(void)\n" "{\n" - " extern int __wine_main_argc;\n" - " extern char **__wine_main_argv;\n" " STARTUPINFOA info;\n" " char *cmdline = GetCommandLineA();\n" - " int bcount=0, in_quotes=0;\n" + " int ret, bcount=0, in_quotes=0;\n" " while (*cmdline) {\n" " if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n" " else if (*cmdline=='\\\\') bcount++;\n" @@ -631,56 +649,14 @@ void BuildSpec32File( FILE *outfile ) " while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n" " GetStartupInfoA( &info );\n" " if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n" - " _ARGC = __wine_main_argc;\n" - " _ARGV = __wine_main_argv;\n" - " ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n" - "}\n\n", init_func, init_func ); - init_func = "__wine_exe_main"; - subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; - break; - case SPEC_MODE_GUIEXE_UNICODE: - if (!init_func) init_func = "WinMain"; - fprintf( outfile, - "\ntypedef unsigned short WCHAR;\n" - "typedef struct {\n" - " unsigned int cb;\n" - " char *lpReserved, *lpDesktop, *lpTitle;\n" - " unsigned int dwX, dwY, dwXSize, dwYSize;\n" - " unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n" - " unsigned short wShowWindow, cbReserved2;\n" - " char *lpReserved2;\n" - " void *hStdInput, *hStdOutput, *hStdError;\n" - "} STARTUPINFOA;\n" - "int _ARGC;\n" - "WCHAR **_ARGV;\n" - "extern int __stdcall %s(void *,void *,char *,int);\n" - "extern char * __stdcall GetCommandLineA(void);\n" - "extern void * __stdcall GetModuleHandleA(char *);\n" - "extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n" - "extern void __stdcall ExitProcess(unsigned int);\n" - "static void __wine_exe_main(void)\n" - "{\n" - " extern int __wine_main_argc;\n" - " extern WCHAR **__wine_main_wargv;\n" - " STARTUPINFOA info;\n" - " char *cmdline = GetCommandLineA();\n" - " int bcount=0, in_quotes=0;\n" - " while (*cmdline) {\n" - " if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n" - " else if (*cmdline=='\\\\') bcount++;\n" - " else if (*cmdline=='\\\"') {\n" - " if ((bcount & 1)==0) in_quotes=!in_quotes;\n" - " bcount=0;\n" - " }\n" - " else bcount=0;\n" - " cmdline++;\n" - " }\n" - " while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n" - " GetStartupInfoA( &info );\n" - " if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n" - " _ARGC = __wine_main_argc;\n" - " _ARGV = __wine_main_wargv;\n" - " ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n" +#ifdef HAVE_LINKER_INIT_FINI + " _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" + " ret = %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow );\n" + " _fini();\n" +#else + " ret = %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow );\n" +#endif + " ExitProcess( ret );\n" "}\n\n", init_func, init_func ); init_func = "__wine_exe_main"; subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; @@ -688,17 +664,19 @@ void BuildSpec32File( FILE *outfile ) case SPEC_MODE_CUIEXE: if (!init_func) init_func = "main"; fprintf( outfile, - "\nint _ARGC;\n" - "char **_ARGV;\n" - "extern void __stdcall ExitProcess(int);\n" + "\nextern void __stdcall ExitProcess(int);\n" "static void __wine_exe_main(void)\n" "{\n" + " int ret;\n" " extern int %s( int argc, char *argv[] );\n" - " extern int __wine_main_argc;\n" - " extern char **__wine_main_argv;\n" - " _ARGC = __wine_main_argc;\n" - " _ARGV = __wine_main_argv;\n" - " ExitProcess( %s( _ARGC, _ARGV ) );\n" +#ifdef HAVE_LINKER_INIT_FINI + " _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" + " ret = %s( __wine_main_argc, __wine_main_argv );\n" + " _fini();\n" +#else + " ret = %s( __wine_main_argc, __wine_main_argv );\n" +#endif + " ExitProcess( ret );\n" "}\n\n", init_func, init_func ); init_func = "__wine_exe_main"; subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; @@ -706,18 +684,19 @@ void BuildSpec32File( FILE *outfile ) case SPEC_MODE_CUIEXE_UNICODE: if (!init_func) init_func = "wmain"; fprintf( outfile, - "\ntypedef unsigned short WCHAR;\n" - "int _ARGC;\n" - "WCHAR **_ARGV;\n" - "extern void __stdcall ExitProcess(int);\n" + "\nextern void __stdcall ExitProcess(int);\n" "static void __wine_exe_main(void)\n" "{\n" - " extern int %s( int argc, WCHAR *argv[] );\n" - " extern int __wine_main_argc;\n" - " extern WCHAR **__wine_main_wargv;\n" - " _ARGC = __wine_main_argc;\n" - " _ARGV = __wine_main_wargv;\n" - " ExitProcess( %s( _ARGC, _ARGV ) );\n" + " int ret;\n" + " extern int %s( int argc, unsigned short *argv[] );\n" +#ifdef HAVE_LINKER_INIT_FINI + " _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" + " ret = %s( __wine_main_argc, __wine_main_wargv );\n" + " _fini();\n" +#else + " ret = %s( __wine_main_argc, __wine_main_wargv );\n" +#endif + " ExitProcess( ret );\n" "}\n\n", init_func, init_func ); init_func = "__wine_exe_main"; subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; @@ -787,7 +766,7 @@ void BuildSpec32File( FILE *outfile ) fprintf( outfile, " { 0x%04x,\n", IMAGE_NT_OPTIONAL_HDR_MAGIC ); /* Magic */ fprintf( outfile, " 0, 0,\n" ); /* Major/MinorLinkerVersion */ fprintf( outfile, " 0, 0, 0,\n" ); /* SizeOfCode/Data */ - fprintf( outfile, " %s,\n", init_func ? init_func : "DllMain" ); /* AddressOfEntryPoint */ + fprintf( outfile, " %s,\n", init_func ); /* AddressOfEntryPoint */ fprintf( outfile, " 0, __wine_spec_data_start,\n" ); /* BaseOfCode/Data */ fprintf( outfile, " __wine_spec_pe_header,\n" ); /* ImageBase */ fprintf( outfile, " %ld,\n", page_size ); /* SectionAlignment */ @@ -818,17 +797,16 @@ void BuildSpec32File( FILE *outfile ) /* Output the DLL constructor */ - sprintf( constructor, "__wine_spec_%s_init", make_c_identifier(dll_file_name) ); - output_dll_init( outfile, constructor, NULL ); - +#ifndef HAVE_LINKER_INIT_FINI + output_dll_init( outfile, "__wine_spec_init", NULL ); +#endif fprintf( outfile, - "void %s(void)\n" + "void __wine_spec_init(void)\n" "{\n" " extern void __wine_dll_register( const struct image_nt_headers *, const char * );\n" - " extern void *__wine_dbg_register( char * const *, int );\n" " __wine_dll_register( &nt_header, \"%s\" );\n" "}\n", - constructor, dll_file_name ); + dll_file_name ); } @@ -942,8 +920,8 @@ void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv ) fprintf( outfile, "#ifdef __GNUC__\n" - "static void __wine_dbg_%s_init(void) __attribute__((constructor));\n" - "static void __wine_dbg_%s_fini(void) __attribute__((destructor));\n" + "void __wine_dbg_%s_init(void) __attribute__((constructor));\n" + "void __wine_dbg_%s_fini(void) __attribute__((destructor));\n" "#else\n" "static void __asm__dummy_dll_init(void) {\n", prefix, prefix ); @@ -971,21 +949,15 @@ void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv ) #else #error You need to define the DLL constructor for your architecture #endif - fprintf( outfile, "}\n#endif /* defined(__GNUC__) */\n" ); + fprintf( outfile, "}\n#endif /* defined(__GNUC__) */\n\n" ); fprintf( outfile, - "\n#ifdef __GNUC__\n" - "static\n" - "#endif\n" "void __wine_dbg_%s_init(void)\n" "{\n" " extern void *__wine_dbg_register( char * const *, int );\n" - " debug_registration = __wine_dbg_register( debug_channels, %d );\n" - "}\n", prefix, nr_debug ); + " if (!debug_registration) debug_registration = __wine_dbg_register( debug_channels, %d );\n" + "}\n\n", prefix, nr_debug ); fprintf( outfile, - "\n#ifdef __GNUC__\n" - "static\n" - "#endif\n" "void __wine_dbg_%s_fini(void)\n" "{\n" " extern void __wine_dbg_unregister( void* );\n"