Brendan Shanks : ntdll: Set up 32-bit segments to support Wow64 on macOS 10.15+.

Alexandre Julliard julliard at winehq.org
Thu May 26 15:46:27 CDT 2022


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

Author: Brendan Shanks <bshanks at codeweavers.com>
Date:   Fri May 13 15:26:23 2022 -0700

ntdll: Set up 32-bit segments to support Wow64 on macOS 10.15+.

Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/signal_x86_64.c | 132 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 703f46b0d4e..e3179e2f1b0 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -208,6 +208,8 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel,
 
 #elif defined (__APPLE__)
 
+#include <i386/user_ldt.h>
+
 #define RAX_sig(context)     ((context)->uc_mcontext->__ss.__rax)
 #define RBX_sig(context)     ((context)->uc_mcontext->__ss.__rbx)
 #define RCX_sig(context)     ((context)->uc_mcontext->__ss.__rcx)
@@ -2833,6 +2835,80 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
 }
 
 
+/***********************************************************************
+ *           LDT support
+ */
+
+#define LDT_SIZE 8192
+
+#define LDT_FLAGS_DATA      0x13  /* Data segment */
+#define LDT_FLAGS_CODE      0x1b  /* Code segment */
+#define LDT_FLAGS_32BIT     0x40  /* Segment is 32-bit (code or stack) */
+#define LDT_FLAGS_ALLOCATED 0x80  /* Segment is allocated */
+
+static ULONG first_ldt_entry = 32;
+
+struct ldt_copy
+{
+    void         *base[LDT_SIZE];
+    unsigned int  limit[LDT_SIZE];
+    unsigned char flags[LDT_SIZE];
+} __wine_ldt_copy;
+
+static pthread_mutex_t ldt_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static inline void *ldt_get_base( LDT_ENTRY ent )
+{
+    return (void *)(ent.BaseLow |
+                    (ULONG_PTR)ent.HighWord.Bits.BaseMid << 16 |
+                    (ULONG_PTR)ent.HighWord.Bits.BaseHi << 24);
+}
+
+static inline unsigned int ldt_get_limit( LDT_ENTRY ent )
+{
+    unsigned int limit = ent.LimitLow | (ent.HighWord.Bits.LimitHi << 16);
+    if (ent.HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff;
+    return limit;
+}
+
+static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char flags )
+{
+    LDT_ENTRY entry;
+
+    entry.BaseLow                   = (WORD)(ULONG_PTR)base;
+    entry.HighWord.Bits.BaseMid     = (BYTE)((ULONG_PTR)base >> 16);
+    entry.HighWord.Bits.BaseHi      = (BYTE)((ULONG_PTR)base >> 24);
+    if ((entry.HighWord.Bits.Granularity = (limit >= 0x100000))) limit >>= 12;
+    entry.LimitLow                  = (WORD)limit;
+    entry.HighWord.Bits.LimitHi     = limit >> 16;
+    entry.HighWord.Bits.Dpl         = 3;
+    entry.HighWord.Bits.Pres        = 1;
+    entry.HighWord.Bits.Type        = flags;
+    entry.HighWord.Bits.Sys         = 0;
+    entry.HighWord.Bits.Reserved_0  = 0;
+    entry.HighWord.Bits.Default_Big = (flags & LDT_FLAGS_32BIT) != 0;
+    return entry;
+}
+
+static void ldt_set_entry( WORD sel, LDT_ENTRY entry )
+{
+    int index = sel >> 3;
+
+#if defined(__APPLE__)
+    if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt");
+#else
+    fprintf( stderr, "No LDT support on this platform\n" );
+    exit(1);
+#endif
+
+    __wine_ldt_copy.base[index]  = ldt_get_base( entry );
+    __wine_ldt_copy.limit[index] = ldt_get_limit( entry );
+    __wine_ldt_copy.flags[index] = (entry.HighWord.Bits.Type |
+                                    (entry.HighWord.Bits.Default_Big ? LDT_FLAGS_32BIT : 0) |
+                                    LDT_FLAGS_ALLOCATED);
+}
+
+
 /**********************************************************************
  *           get_thread_ldt_entry
  */
@@ -2871,8 +2947,25 @@ NTSTATUS signal_alloc_thread( TEB *teb )
 
     if (teb->WowTebOffset)
     {
-        if (fs32_sel)
-            thread_data->fs = fs32_sel;
+        if (!fs32_sel)
+        {
+            void *teb32 = (char *)teb + teb->WowTebOffset;
+            sigset_t sigset;
+            int idx;
+            LDT_ENTRY entry = ldt_make_entry( teb32, page_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
+
+            server_enter_uninterrupted_section( &ldt_mutex, &sigset );
+            for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
+            {
+                if (__wine_ldt_copy.flags[idx]) continue;
+                ldt_set_entry( (idx << 3) | 7, entry );
+                break;
+            }
+            server_leave_uninterrupted_section( &ldt_mutex, &sigset );
+            if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS;
+            thread_data->fs = (idx << 3) | 7;
+        }
+        else thread_data->fs = fs32_sel;
     }
     return STATUS_SUCCESS;
 }
@@ -2883,6 +2976,15 @@ NTSTATUS signal_alloc_thread( TEB *teb )
  */
 void signal_free_thread( TEB *teb )
 {
+    struct amd64_thread_data *thread_data = (struct amd64_thread_data *)&teb->GdiTebBatch;
+    sigset_t sigset;
+
+    if (teb->WowTebOffset && !fs32_sel)
+    {
+        server_enter_uninterrupted_section( &ldt_mutex, &sigset );
+        __wine_ldt_copy.flags[thread_data->fs >> 3] = 0;
+        server_leave_uninterrupted_section( &ldt_mutex, &sigset );
+    }
 }
 
 #ifdef __APPLE__
@@ -3012,6 +3114,32 @@ void signal_init_process(void)
         }
         else ERR_(seh)( "failed to allocate %%fs selector\n" );
     }
+#elif defined(__APPLE__)
+    if (NtCurrentTeb()->WowTebOffset)
+    {
+        void *teb32 = (char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset;
+        LDT_ENTRY cs32_entry, fs32_entry;
+        int idx;
+
+        cs32_entry = ldt_make_entry( NULL, -1, LDT_FLAGS_CODE | LDT_FLAGS_32BIT );
+        fs32_entry = ldt_make_entry( teb32, page_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
+
+        for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
+        {
+            if (__wine_ldt_copy.flags[idx]) continue;
+            cs32_sel = (idx << 3) | 7;
+            ldt_set_entry( cs32_sel, cs32_entry );
+            break;
+        }
+
+        for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
+        {
+            if (__wine_ldt_copy.flags[idx]) continue;
+            amd64_thread_data()->fs = (idx << 3) | 7;
+            ldt_set_entry( amd64_thread_data()->fs, fs32_entry );
+            break;
+        }
+    }
 #endif
 
     sig_act.sa_mask = server_block_set;




More information about the wine-cvs mailing list