Alexandre Julliard : winebuild: Add -import entry point flag to generate hotpatchable import thunks.

Alexandre Julliard julliard at winehq.org
Fri Jun 21 16:44:17 CDT 2019


Module: wine
Branch: master
Commit: cf619dd419ca371602d44f19236cf557b222eddf
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=cf619dd419ca371602d44f19236cf557b222eddf

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Jun 21 12:08:44 2019 +0200

winebuild: Add -import entry point flag to generate hotpatchable import thunks.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 tools/make_specfiles             |  1 +
 tools/winebuild/build.h          | 31 +++++++-------
 tools/winebuild/import.c         |  5 +++
 tools/winebuild/parser.c         |  1 +
 tools/winebuild/spec32.c         | 90 +++++++++++++++++++++++++++++++---------
 tools/winebuild/winebuild.man.in |  7 ++++
 6 files changed, 101 insertions(+), 34 deletions(-)

diff --git a/tools/make_specfiles b/tools/make_specfiles
index c2fa929..7b9115e 100755
--- a/tools/make_specfiles
+++ b/tools/make_specfiles
@@ -591,6 +591,7 @@ sub update_spec_file($)
             $flags = $parent{flags};
             $flags =~ s/-ordinal\s*// if $descr{ordinal} eq "@";
             $flags =~ s/-noname\s*// if $descr{ordinal} eq "@";
+            $flags =~ s/-import\s*//;
             if ($descr{flags} =~ /-private/)  # preserve -private flag
             {
                 $flags = "-private " . $flags unless $flags =~ /-private/;
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index ad6e2a8..43a0dd2 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -168,21 +168,22 @@ struct strarray
 };
 
 /* entry point flags */
-#define FLAG_NORELAY   0x01  /* don't use relay debugging for this function */
-#define FLAG_NONAME    0x02  /* don't export function by name */
-#define FLAG_RET16     0x04  /* function returns a 16-bit value */
-#define FLAG_RET64     0x08  /* function returns a 64-bit value */
-#define FLAG_REGISTER  0x10  /* use register calling convention */
-#define FLAG_PRIVATE   0x20  /* function is private (cannot be imported) */
-#define FLAG_ORDINAL   0x40  /* function should be imported by ordinal */
-#define FLAG_THISCALL  0x80  /* use thiscall calling convention */
-#define FLAG_FASTCALL  0x100 /* use fastcall calling convention */
-
-#define FLAG_FORWARD   0x200  /* function is a forwarded name */
-#define FLAG_EXT_LINK  0x400  /* function links to an external symbol */
-#define FLAG_EXPORT32  0x800  /* 32-bit export in 16-bit spec file */
-
-#define FLAG_CPU(cpu)  (0x01000 << (cpu))
+#define FLAG_NORELAY   0x0001  /* don't use relay debugging for this function */
+#define FLAG_NONAME    0x0002  /* don't export function by name */
+#define FLAG_RET16     0x0004  /* function returns a 16-bit value */
+#define FLAG_RET64     0x0008  /* function returns a 64-bit value */
+#define FLAG_REGISTER  0x0010  /* use register calling convention */
+#define FLAG_PRIVATE   0x0020  /* function is private (cannot be imported) */
+#define FLAG_ORDINAL   0x0040  /* function should be imported by ordinal */
+#define FLAG_THISCALL  0x0080  /* use thiscall calling convention */
+#define FLAG_FASTCALL  0x0100  /* use fastcall calling convention */
+#define FLAG_IMPORT    0x0200  /* export is imported from another module */
+
+#define FLAG_FORWARD   0x1000  /* function is a forwarded name */
+#define FLAG_EXT_LINK  0x2000  /* function links to an external symbol */
+#define FLAG_EXPORT32  0x4000  /* 32-bit export in 16-bit spec file */
+
+#define FLAG_CPU(cpu)  (0x10000 << (cpu))
 #define FLAG_CPU_MASK  (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
 #define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
 #define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 7cf0655..8c32b73 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -838,6 +838,11 @@ static void output_immediate_imports(void)
             for (j = 0; j < import->nb_imports; j++)
             {
                 struct import_func *func = &import->imports[j];
+                if (i)
+                {
+                    if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
+                    else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
+                }
                 if (func->name)
                     output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
                             get_asm_ptr_keyword(), import->c_name, func->name );
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index bec9f52..3191efa 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -70,6 +70,7 @@ static const char * const FlagNames[] =
     "ordinal",     /* FLAG_ORDINAL */
     "thiscall",    /* FLAG_THISCALL */
     "fastcall",    /* FLAG_FASTCALL */
+    "import",      /* FLAG_IMPORT */
     NULL
 };
 
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index f1dedcc..855e6d8 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -379,9 +379,11 @@ static void output_relay_debug( DLLSPEC *spec )
 void output_exports( DLLSPEC *spec )
 {
     int i, fwd_size = 0;
+    int needs_imports = 0;
     int needs_relay = has_relays( spec );
     int nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
     const char *func_ptr = (target_platform == PLATFORM_WINDOWS) ? ".rva" : get_asm_ptr_keyword();
+    const char *name;
 
     if (!nr_exports) return;
 
@@ -430,6 +432,13 @@ void output_exports( DLLSPEC *spec )
                 output( "\t%s .L__wine_spec_forwards+%u\n", func_ptr, fwd_size );
                 fwd_size += strlen(odp->link_name) + 1;
             }
+            else if ((odp->flags & FLAG_IMPORT) && (target_cpu == CPU_x86 || target_cpu == CPU_x86_64))
+            {
+                name = odp->name ? odp->name : odp->export_name;
+                if (name) output( "\t%s %s_%s\n", func_ptr, asm_name("__wine_spec_imp"), name );
+                else output( "\t%s %s_%u\n", func_ptr, asm_name("__wine_spec_imp"), i );
+                needs_imports = 1;
+            }
             else if (odp->flags & FLAG_EXT_LINK)
             {
                 output( "\t%s %s_%s\n", func_ptr, asm_name("__wine_spec_ext_link"), odp->link_name );
@@ -503,32 +512,75 @@ void output_exports( DLLSPEC *spec )
 
     /* output relays */
 
-    if (target_platform == PLATFORM_WINDOWS)
+    if (needs_relay)
     {
-        if (!needs_relay) return;
-        output( "\t.data\n" );
-        output( "\t.align %d\n", get_alignment(get_ptr_size()) );
+        if (target_platform == PLATFORM_WINDOWS)
+        {
+            output( "\t.data\n" );
+            output( "\t.align %d\n", get_alignment(get_ptr_size()) );
+        }
+        else
+        {
+            output( "\t.align %d\n", get_alignment(get_ptr_size()) );
+            output( ".L__wine_spec_exports_end:\n" );
+        }
+
+        output( ".L__wine_spec_relay_descr:\n" );
+        output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() );  /* magic */
+        output( "\t%s 0\n", get_asm_ptr_keyword() );           /* relay func */
+        output( "\t%s 0\n", get_asm_ptr_keyword() );           /* private data */
+        output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
+        output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
+        output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
+
+        output_relay_debug( spec );
     }
-    else
+    else if (target_platform != PLATFORM_WINDOWS)
     {
-        output( "\t.align %d\n", get_alignment(get_ptr_size()) );
-        output( ".L__wine_spec_exports_end:\n" );
-        if (!needs_relay)
-        {
+            output( "\t.align %d\n", get_alignment(get_ptr_size()) );
+            output( ".L__wine_spec_exports_end:\n" );
             output( "\t%s 0\n", get_asm_ptr_keyword() );
-            return;
-        }
     }
 
-    output( ".L__wine_spec_relay_descr:\n" );
-    output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() );  /* magic */
-    output( "\t%s 0\n", get_asm_ptr_keyword() );           /* relay func */
-    output( "\t%s 0\n", get_asm_ptr_keyword() );           /* private data */
-    output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
-    output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
-    output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
+    /* output import thunks */
 
-    output_relay_debug( spec );
+    if (!needs_imports) return;
+    output( "\t.text\n" );
+    for (i = spec->base; i <= spec->limit; i++)
+    {
+        ORDDEF *odp = spec->ordinals[i];
+        if (!odp) continue;
+        if (!(odp->flags & FLAG_IMPORT)) continue;
+
+        name = odp->name ? odp->name : odp->export_name;
+
+        output( "\t.align %d\n", get_alignment(4) );
+        output( "\t.long 0x90909090,0x90909090\n" );
+        if (name) output( "%s_%s:\n", asm_name("__wine_spec_imp"), name );
+        else output( "%s_%u:\n", asm_name("__wine_spec_imp"), i );
+        output_cfi( ".cfi_startproc" );
+
+        switch (target_cpu)
+        {
+        case CPU_x86:
+            output( "\t.byte 0x8b,0xff,0x55,0x8b,0xec,0x5d\n" );  /* hotpatch prolog */
+            if (UsePIC)
+            {
+                output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
+                output( "1:\tjmp *__imp_%s-1b(%%eax)\n", asm_name( get_link_name( odp )));
+                needs_get_pc_thunk = 1;
+            }
+            else output( "\tjmp *__imp_%s\n", asm_name( get_link_name( odp )));
+            break;
+        case CPU_x86_64:
+            output( "\t.byte 0x48\n" );  /* hotpatch prolog */
+            output( "\tjmp *__imp_%s(%%rip)\n", asm_name( get_link_name( odp )));
+            break;
+        default:
+            assert(0);
+        }
+        output_cfi( ".cfi_endproc" );
+    }
 }
 
 
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in
index e9386f9..1b9b1b0 100644
--- a/tools/winebuild/winebuild.man.in
+++ b/tools/winebuild/winebuild.man.in
@@ -315,6 +315,13 @@ The function uses the
 calling convention (first two parameters in %ecx/%edx registers on
 i386).
 .TP
+.B -import
+The function is imported from another module. This can be used instead
+of a
+.I forward
+specification when an application expects to find the function's
+implementation inside the dll.
+.TP
 .RE
 .BI -arch= cpu\fR[\fB,\fIcpu\fR]
 The entry point is only available on the specified CPU




More information about the wine-cvs mailing list