steam web browsing on OS X

Jacek Caban jacek at codeweavers.com
Mon Nov 2 08:43:07 CST 2015


On 11/02/15 13:15, Jacek Caban wrote:
> Hi Sebastian,
>
> On 11/02/15 12:16, Sebastian Lackner wrote:
>> On 02.11.2015 11:12, Jacek Caban wrote:
>>> Sure. The idea is to pass relative addresses instead to
>>> call_syscall_func and let it handle that. Calling call_syscall_func
>>> itself may use a constant address if we let it live in user shared data.
>>> Did you try that? That's one of those things that one has to try to see
>>> if it works in practice.
>> Yes, I also looked at this approach. The difficult part to get this correct
>> is to initialize user shared data as early as possible, without any call to
>> a wrapper function before that. Please note that its not sufficient to wrap
>> calls from other dlls, even some ntdll-internal calls have to go through the
>> wrappers (for example when loading a library). Those are implemented in
>> ntdll usermode on Windows.
>>
>>> Also I believe that using winebuild for that is the right way.
>> I already tried it out in practice and partially disagree. As mentioned above,
>> its not sufficient to put autogenerated wrappers between the implementation
>> and the ntdll exports. Exactly the same wrappers have to be used from inside
>> of the ntdll loader code for example. This means, even if the thunks are
>> generated somewhere else, we still have to add them to one of the wine header
>> files. If we do not want to generate thunks for all architectures, we might
>> even have to add them twice, one time as typedef, and the second time a #define
>> as fallback for unsupported architectures.
>>
>> I'm not saying that its impossible to do it this way, but compared to thiscalls,
>> which could easily be generated by winebuild, a macro is similar good here imho.
>> If you want to look into the idea to autogenerate thunks, here is one of my
>> work-in-progress patches (based on Erichs work): http://ix.io/lLz
> See attached patches. On the quick look it seems similar to the one you
> mentioned, except it avoids text relocations. The patch is definitely
> not finished nor ready for proper review, but it's enough to get things
> to build and run. I haven't even tested that with Chromium nor other
> apps that need it (well, I haven't tested it at all, really).
>
> Patch 1 is the interesting one. Patch 2 just marks needed functions as
> syscalls.
>
> Patch 3 is to show how to address your concerns about going through
> thunks from inside ntdll. Those use macros from your patch except their
> meaning is reverted. I chose two calls that I know will need to be fixed
> for Office. I don't know how much more calls will need to be changed. In
> general, we can't avoid such problems: we will either need to explicitly
> mark calls that need to go through the thunk or those that don't. I
> chose the first variant because it seems cleaner and more in line with
> how winebuild works. I do believe that implementing things to work the
> other way around is also possible in winebuild.
>
> Cheers,
> Jacek

It seems that my mail didn't make it to wine-devel, probably due to
attachment size. I'm resending without patch 2.

Cheers,
Jacek
-------------- next part --------------
From c872a68cf0329f84ae39d6ac7f0cc64878698cc4 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Mon, 2 Nov 2015 12:50:36 +0100
Subject: [PATCH 1/3] winebuild: Added support for syscall wrapper thunks.
To: wine-patches <wine-patches at winehq.org>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 dlls/ntdll/thread.c      | 25 ++++++++++++++++++++--
 tools/winebuild/build.h  |  1 +
 tools/winebuild/parser.c |  1 +
 tools/winebuild/spec32.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index aaf7a71..88b5fbe 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -202,6 +202,25 @@ static ULONG64 get_dyld_image_info_addr(void)
 }
 #endif  /* __APPLE__ */
 
+extern char *__wine_spec_nt_header;
+
+#include "pshpack1.h"
+static struct {
+    BYTE add_esp[3];
+    BYTE add_eax;
+    DWORD module_base;
+    BYTE mov_eax_eax[2];
+    BYTE jmp_eax[2];
+    WORD ret;
+} thunk = {
+    {0x83,0xc4,0x04}, /* addl $4,%esp */
+    0x05, 0,          /* addl __wine_spec_nt_header,%eax */
+    {0x8b,0x00},      /* movl 0(%eax),%eax */
+    {0xff,0xe0},      /* jmp *%eax */
+    0xc3              /* ret */
+};
+#include "poppack.h"
+
 /***********************************************************************
  *           thread_init
  *
@@ -230,7 +249,7 @@ HANDLE thread_init(void)
     addr = (void *)0x7ffe0000;
     size = 0x10000;
     status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size,
-                                      MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
+                                      MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
     if (status)
     {
         MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
@@ -238,8 +257,10 @@ HANDLE thread_init(void)
     }
     user_shared_data = addr;
 
-    /* allocate and initialize the PEB */
+    thunk.module_base = (DWORD)&__wine_spec_nt_header;
+    memcpy(&user_shared_data->SystemCall, &thunk, sizeof(thunk));
 
+    /* allocate and initialize the PEB */
     addr = NULL;
     size = sizeof(*peb);
     NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size,
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index 4a71eed..e67896c 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -171,6 +171,7 @@ struct strarray
 #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_SYSCALL   0x80  /* function implements NT syscall */
 
 #define FLAG_FORWARD   0x100  /* function is a forwarded name */
 #define FLAG_EXT_LINK  0x200  /* function links to an external symbol */
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index 1d7b84e..021356f 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -69,6 +69,7 @@ static const char * const FlagNames[] =
     "register",    /* FLAG_REGISTER */
     "private",     /* FLAG_PRIVATE */
     "ordinal",     /* FLAG_ORDINAL */
+    "syscall",     /* FLAG_SYSCALL */
     NULL
 };
 
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index cb56abe..d375706 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -270,6 +270,55 @@ static void output_relay_debug( DLLSPEC *spec )
     }
 }
 
+static void output_syscall_wrappers( DLLSPEC *spec )
+{
+    int i, emited_syscalls = 0, syscall_cnt = 0;
+    char **syscall_entries, *sym_name;
+    ORDDEF *odp;
+
+    for (odp = spec->entry_points; odp < spec->entry_points + spec->nb_entry_points; odp++)
+        if(odp->flags & FLAG_SYSCALL)
+            syscall_cnt++;
+
+    if(!syscall_cnt)
+        return;
+
+    syscall_entries = xmalloc(syscall_cnt*sizeof(*syscall_entries));
+
+    output("\t.text\n");
+
+    for (odp = spec->entry_points; odp < spec->entry_points + spec->nb_entry_points; odp++) {
+        if(!(odp->flags & FLAG_SYSCALL))
+            continue;
+
+        for(i=0; i < emited_syscalls; i++) {
+            if(!strcmp(odp->link_name, syscall_entries[i]))
+                break;
+        }
+        if(i < emited_syscalls)
+            continue; /* already emited */
+
+        syscall_entries[emited_syscalls] = odp->link_name;
+
+        sym_name = strmake("__syscall_%s", odp->link_name);
+        output( "%s\n", asm_globl(sym_name) );
+        output( "\tmovl $.L__wine_spec_syscalls+%u-.L__wine_spec_rva_base,%%eax\n", emited_syscalls*4);
+        output( "\tmovl $0x7ffe0300,%%edx\n" );
+        output( "\tcall *%%edx\n" );
+        output( "\tret $%u\n", get_args_size(odp));
+        free(sym_name);
+        emited_syscalls++;
+    }
+
+    output( "\n\t.data\n" );
+    output( ".L__wine_spec_syscalls:\n" );
+
+    for (i=0; i < emited_syscalls; i++)
+        output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(syscall_entries[i]) );
+
+    free(syscall_entries);
+}
+
 /*******************************************************************
  *         output_exports
  *
@@ -332,6 +381,10 @@ void output_exports( DLLSPEC *spec )
                 output( "\t%s %s_%s\n",
                          get_asm_ptr_keyword(), asm_name("__wine_spec_ext_link"), odp->link_name );
             }
+            else if (odp->flags & FLAG_SYSCALL)
+            {
+                output( "\t%s %s_%s\n", get_asm_ptr_keyword(), asm_name("__syscall"), odp->link_name );
+            }
             else
             {
                 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
@@ -622,6 +675,7 @@ void BuildSpec32File( DLLSPEC *spec )
     output_stubs( spec );
     output_exports( spec );
     output_imports( spec );
+    output_syscall_wrappers( spec );
     if (is_undefined( "__wine_call_from_regs" )) output_asm_relays();
     output_resources( spec );
     output_gnu_stack_note();
-- 
2.4.9

-------------- next part --------------
From 6f085b2fbcb13a87e1078c421e4a9f6b2e6d421b Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Mon, 2 Nov 2015 12:58:48 +0100
Subject: [PATCH 3/3] ntdll: Call NtOpenFile via syscall wrapper in loader.
To: wine-patches <wine-patches at winehq.org>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 dlls/ntdll/loader.c     |  4 ++--
 dlls/ntdll/ntdll_misc.h | 11 +++++++++++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 831f049..e009f0e 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2149,7 +2149,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
             attr.ObjectName = &nt_name;
             attr.SecurityDescriptor = NULL;
             attr.SecurityQualityOfService = NULL;
-            if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
+            if (SYSCALL(NtOpenFile)( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
             goto found;
         }
 
@@ -2184,7 +2184,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
         attr.ObjectName = &nt_name;
         attr.SecurityDescriptor = NULL;
         attr.SecurityQualityOfService = NULL;
-        if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
+        if (SYSCALL(NtOpenFile)( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
     }
 found:
     RtlFreeUnicodeString( &nt_name );
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index cbd19db..7d5331f 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -260,8 +260,19 @@ extern HANDLE keyed_event DECLSPEC_HIDDEN;
                        ".byte 0x6a," #args "\n\t" /* pushl $args */     \
                        "call " __ASM_NAME("__wine_call_from_regs") "\n\t" \
                        "ret $(4*" #args ")" ) /* fake ret to make copy protections happy */
+
+#define SYSCALL( name ) __syscall_ ## name
+#define DECLARE_SYSCALL_ENTRYPOINT( name )  extern typeof( name ) SYSCALL( name )
+
+#else
+
+#define SYSCALL( name ) name
+#define DECLARE_SYSCALL_ENTRYPOINT( name )
+
 #endif
 
+DECLARE_SYSCALL_ENTRYPOINT(NtOpenFile);
+
 #define HASH_STRING_ALGORITHM_DEFAULT  0
 #define HASH_STRING_ALGORITHM_X65599   1
 #define HASH_STRING_ALGORITHM_INVALID  0xffffffff
-- 
2.4.9



More information about the wine-devel mailing list