[PATCH v2] winebuild: Find main/wmain in static libraries.

Kevin Puetz PuetzKevinA at JohnDeere.com
Fri Nov 20 11:32:50 CST 2020


Have the winebuild -spec.o include an undefined .globl referencing
symbols we know the winecrt0 entry point will eventually reference,
so ld knows about what it needs before scanning library archives.

Signed-off-by: Kevin Puetz <PuetzKevinA at JohnDeere.com>
---
This one had fuzz in spec32.c from d5c089f5fa71e2ae568b2f1bcb9158223c552040
Still applied correctly, but marvin apparently doesn't like fuzz. Oops.
---

wine.exe.so files set __wine_spec_exe_entry as the entry point.
Therefore the linker is not initially looking for main and will pass
over objects in lib.a archives that might provide it. When it gets to
libwinecrt0.a is reached, it finds __wine_spec_exe_entry and learns
that this wants main, but the resulting rescan will find the winecrt0
definition in terms of WinMain, before rescanning earlier libraries.

So only a direct .o file (which is never passed over) can override
the winecrt0 definition, and libraries like -lgtest_main do not work.
---
 tools/winebuild/build.h  |  2 ++
 tools/winebuild/main.c   | 22 ++++++++++++++++++++--
 tools/winebuild/spec32.c | 12 ++++++++++++
 tools/winegcc/winegcc.c  |  4 ++--
 4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index 03715af9563..a4b9bc97e3e 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -136,6 +136,7 @@ typedef struct
     int              subsystem;          /* subsystem id */
     int              subsystem_major;    /* subsystem version major number */
     int              subsystem_minor;    /* subsystem version minor number */
+    int              unicode_app;        /* default to unicode entry point */
     ORDDEF          *entry_points;       /* dll entry points */
     ORDDEF         **names;              /* array of entry point names (points into entry_points) */
     ORDDEF         **ordinals;           /* array of dll ordinals (points into entry_points) */
@@ -299,6 +300,7 @@ extern void output_gnu_stack_note(void);
 extern void add_import_dll( const char *name, const char *filename );
 extern void add_delayed_import( const char *name );
 extern void add_extra_ld_symbol( const char *name );
+extern void add_spec_extra_ld_symbol( const char *name );
 extern void read_undef_symbols( DLLSPEC *spec, char **argv );
 extern void resolve_imports( DLLSPEC *spec );
 extern int is_undefined( const char *name );
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index 0e5e1627dda..68137b0f4c2 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -396,8 +396,25 @@ static const char *get_default_entry_point( const DLLSPEC *spec )
 {
     if (spec->characteristics & IMAGE_FILE_DLL) return "DllMain";
     if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "DriverEntry";
-    if (spec->type == SPEC_WIN16) return "__wine_spec_exe16_entry";
-    return "__wine_spec_exe_entry";
+    if (spec->type == SPEC_WIN16) {
+        add_spec_extra_ld_symbol("WinMain16");
+        return "__wine_spec_exe16_entry";
+    }
+    if (spec->unicode_app) {
+        /* __wine_spec_exe_wentry always calls wmain */
+        add_spec_extra_ld_symbol("wmain");
+        if(spec->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+            add_spec_extra_ld_symbol("wWinMain");
+        }
+        return "__wine_spec_exe_wentry";
+    } else {
+        /* __wine_spec_exe_entry always calls main */
+        add_spec_extra_ld_symbol("main");
+        if(spec->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+            add_spec_extra_ld_symbol("WinMain");
+        }
+        return "__wine_spec_exe_entry";
+    }
 }
 
 /* parse options from the argv array and remove all the recognized ones */
@@ -448,6 +465,7 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
             else if (!strcmp( optarg, "thumb" )) thumb_mode = 1;
             else if (!strcmp( optarg, "no-cygwin" )) use_msvcrt = 1;
             else if (!strcmp( optarg, "unix" )) unix_lib = 1;
+            else if (!strcmp( optarg, "unicode" )) spec->unicode_app = 1;
             else if (!strncmp( optarg, "cpu=", 4 )) cpu_option = xstrdup( optarg + 4 );
             else if (!strncmp( optarg, "fpu=", 4 )) fpu_option = xstrdup( optarg + 4 );
             else if (!strncmp( optarg, "arch=", 5 )) arch_option = xstrdup( optarg + 5 );
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index ba2edfb588f..a12e7d38aac 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -50,6 +50,13 @@ int needs_get_pc_thunk = 0;
 
 static const char builtin_signature[32] = "Wine builtin DLL";
 static const char fakedll_signature[32] = "Wine placeholder DLL";
+static struct strarray spec_extra_ld_symbols = { 0 }; /* list of extra symbols that ld should resolve */
+
+/* add a symbol to the list of extra symbols that ld must resolve */
+void add_spec_extra_ld_symbol( const char *name )
+{
+    strarray_add( &spec_extra_ld_symbols, name, NULL );
+}
 
 static unsigned int hash_filename( const char *name )
 {
@@ -610,6 +617,7 @@ void output_exports( DLLSPEC *spec )
 void output_module( DLLSPEC *spec )
 {
     int machine = 0;
+    int i;
     unsigned int page_size = get_page_size();
     const char *data_dirs[16] = { NULL };
 
@@ -688,6 +696,10 @@ void output_module( DLLSPEC *spec )
     output( "\t.long 0\n" );              /* SizeOfCode */
     output( "\t.long 0\n" );              /* SizeOfInitializedData */
     output( "\t.long 0\n" );              /* SizeOfUninitializedData */
+
+    for (i = 0; i < spec_extra_ld_symbols.count; i++)
+        output( "\t.globl %s\n", asm_name(spec_extra_ld_symbols.str[i]) );
+
     /* note: we expand the AddressOfEntryPoint field on 64-bit by overwriting the BaseOfCode field */
     output( "\t%s %s\n",                  /* AddressOfEntryPoint */
             get_asm_ptr_keyword(), spec->init_func ? asm_name(spec->init_func) : "0" );
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c
index 9268a5dfd1d..cef0832455c 100644
--- a/tools/winegcc/winegcc.c
+++ b/tools/winegcc/winegcc.c
@@ -1245,8 +1245,6 @@ static void build(struct options* opts)
             entry_point = (is_pe && opts->target_cpu == CPU_x86) ? "DriverEntry at 8" : "DriverEntry";
         else if (opts->use_msvcrt && !opts->shared && !opts->win16_app)
             entry_point = opts->unicode_app ? "wmainCRTStartup" : "mainCRTStartup";
-        else if (!is_pe && !opts->shared && opts->unicode_app)
-            entry_point = "__wine_spec_exe_wentry";
     }
     else entry_point = opts->entry_point;
 
@@ -1258,6 +1256,8 @@ static void build(struct options* opts)
     spec_o_name = get_temp_file(output_name, ".spec.o");
     if (opts->force_pointer_size)
         strarray_add(spec_args, strmake("-m%u", 8 * opts->force_pointer_size ));
+    if(opts->unicode_app)
+        strarray_add(spec_args, "-municode");
     strarray_add(spec_args, "-D_REENTRANT");
     if (opts->pic && !is_pe) strarray_add(spec_args, "-fPIC");
     strarray_add(spec_args, opts->shared ? "--dll" : "--exe");



More information about the wine-devel mailing list