user: Allocate 16-bit thunks separately from the window proc structure.
Also make sure the thunk memory block has execute permissions.
This commit is contained in:
parent
354edc476f
commit
2a809c195d
|
@ -45,36 +45,8 @@ WINE_DECLARE_DEBUG_CHANNEL(msg);
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(win);
|
WINE_DEFAULT_DEBUG_CHANNEL(win);
|
||||||
|
|
||||||
#ifdef __i386__
|
|
||||||
|
|
||||||
#include "pshpack1.h"
|
|
||||||
|
|
||||||
/* Window procedure 16-to-32-bit thunk */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
BYTE popl_eax; /* popl %eax (return address) */
|
|
||||||
BYTE pushl_func; /* pushl $proc */
|
|
||||||
struct tagWINDOWPROC *proc;
|
|
||||||
BYTE pushl_eax; /* pushl %eax */
|
|
||||||
BYTE ljmp; /* ljmp relay*/
|
|
||||||
DWORD relay_offset; /* __wine_call_wndproc */
|
|
||||||
WORD relay_sel;
|
|
||||||
} WINPROC_THUNK;
|
|
||||||
|
|
||||||
#include "poppack.h"
|
|
||||||
|
|
||||||
#else /* __i386__ */
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
WNDPROC proc;
|
|
||||||
} WINPROC_THUNK;
|
|
||||||
|
|
||||||
#endif /* __i386__ */
|
|
||||||
|
|
||||||
typedef struct tagWINDOWPROC
|
typedef struct tagWINDOWPROC
|
||||||
{
|
{
|
||||||
WINPROC_THUNK thunk; /* Thunk */
|
|
||||||
BYTE type; /* Function type */
|
BYTE type; /* Function type */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -106,15 +78,6 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||||
};
|
};
|
||||||
static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
|
static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||||
|
|
||||||
static BOOL is_valid_winproc( WINDOWPROC *proc )
|
|
||||||
{
|
|
||||||
/* check alignment */
|
|
||||||
if (((BYTE *)proc - (BYTE *)winproc_array) % sizeof(*proc)) return FALSE;
|
|
||||||
/* check array limits */
|
|
||||||
if (proc < winproc_array || proc >= winproc_array + winproc_used) return FALSE;
|
|
||||||
return (proc->type != WIN_PROC_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find an existing winproc for a given 16-bit function and type */
|
/* find an existing winproc for a given 16-bit function and type */
|
||||||
/* FIXME: probably should do something more clever than a linear search */
|
/* FIXME: probably should do something more clever than a linear search */
|
||||||
static inline WINDOWPROC *find_winproc16( WNDPROC16 func )
|
static inline WINDOWPROC *find_winproc16( WNDPROC16 func )
|
||||||
|
@ -151,43 +114,9 @@ static inline WINDOWPROC *init_winproc(void)
|
||||||
|
|
||||||
if (winproc_used >= MAX_WINPROCS) return NULL;
|
if (winproc_used >= MAX_WINPROCS) return NULL;
|
||||||
proc = &winproc_array[winproc_used++];
|
proc = &winproc_array[winproc_used++];
|
||||||
#ifdef __i386__
|
|
||||||
{
|
|
||||||
static FARPROC16 relay;
|
|
||||||
|
|
||||||
if (!relay) relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
|
|
||||||
|
|
||||||
proc->thunk.popl_eax = 0x58; /* popl %eax */
|
|
||||||
proc->thunk.pushl_func = 0x68; /* pushl $proc */
|
|
||||||
proc->thunk.proc = proc;
|
|
||||||
proc->thunk.pushl_eax = 0x50; /* pushl %eax */
|
|
||||||
proc->thunk.ljmp = 0xea; /* ljmp relay*/
|
|
||||||
proc->thunk.relay_offset = OFFSETOF(relay);
|
|
||||||
proc->thunk.relay_sel = SELECTOROF(relay);
|
|
||||||
}
|
|
||||||
#endif /* __i386__ */
|
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD get_winproc_selector(void)
|
|
||||||
{
|
|
||||||
static LONG winproc_selector;
|
|
||||||
WORD ret;
|
|
||||||
|
|
||||||
if (!(ret = winproc_selector))
|
|
||||||
{
|
|
||||||
LDT_ENTRY entry;
|
|
||||||
WORD sel = wine_ldt_alloc_entries(1);
|
|
||||||
wine_ldt_set_base( &entry, winproc_array );
|
|
||||||
wine_ldt_set_limit( &entry, sizeof(winproc_array) - 1 );
|
|
||||||
wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
|
|
||||||
wine_ldt_set_entry( sel, &entry );
|
|
||||||
if (!(ret = InterlockedCompareExchange( &winproc_selector, sel, 0 ))) ret = sel;
|
|
||||||
else wine_ldt_free_entries( sel, 1 ); /* somebody beat us to it */
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return the window proc for a given handle, or NULL for an invalid handle */
|
/* return the window proc for a given handle, or NULL for an invalid handle */
|
||||||
static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
|
static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
|
||||||
{
|
{
|
||||||
|
@ -197,20 +126,6 @@ static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
|
||||||
return &winproc_array[index];
|
return &winproc_array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the window proc for a given handle, or NULL for an invalid handle */
|
|
||||||
static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
|
|
||||||
{
|
|
||||||
if (HIWORD(handle) == get_winproc_selector())
|
|
||||||
{
|
|
||||||
BYTE *ptr = (BYTE *)winproc_array + LOWORD(handle);
|
|
||||||
/* It must be the thunk address */
|
|
||||||
WINDOWPROC *proc = (WINDOWPROC *)(ptr - FIELD_OFFSET(WINDOWPROC,thunk));
|
|
||||||
if (is_valid_winproc(proc)) return proc;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return handle_to_proc( (WNDPROC)handle );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a handle for a given window proc */
|
/* create a handle for a given window proc */
|
||||||
static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
|
static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
|
||||||
{
|
{
|
||||||
|
@ -248,6 +163,106 @@ static inline WINDOWPROC *alloc_winproc( WNDPROC func, BOOL unicode )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
|
||||||
|
#include "pshpack1.h"
|
||||||
|
|
||||||
|
/* Window procedure 16-to-32-bit thunk */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BYTE popl_eax; /* popl %eax (return address) */
|
||||||
|
BYTE pushl_func; /* pushl $proc */
|
||||||
|
WINDOWPROC *proc;
|
||||||
|
BYTE pushl_eax; /* pushl %eax */
|
||||||
|
BYTE ljmp; /* ljmp relay*/
|
||||||
|
DWORD relay_offset; /* __wine_call_wndproc */
|
||||||
|
WORD relay_sel;
|
||||||
|
} WINPROC_THUNK;
|
||||||
|
|
||||||
|
#include "poppack.h"
|
||||||
|
|
||||||
|
#define MAX_THUNKS (0x10000 / sizeof(WINPROC_THUNK))
|
||||||
|
|
||||||
|
static WINPROC_THUNK *thunk_array;
|
||||||
|
static UINT thunk_selector;
|
||||||
|
static UINT thunk_used;
|
||||||
|
|
||||||
|
/* return the window proc for a given handle, or NULL for an invalid handle */
|
||||||
|
static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
|
||||||
|
{
|
||||||
|
if (HIWORD(handle) == thunk_selector)
|
||||||
|
{
|
||||||
|
UINT index = LOWORD(handle) / sizeof(WINPROC_THUNK);
|
||||||
|
/* check alignment */
|
||||||
|
if (index * sizeof(WINPROC_THUNK) != LOWORD(handle)) return NULL;
|
||||||
|
/* check array limits */
|
||||||
|
if (index >= thunk_used) return NULL;
|
||||||
|
return thunk_array[index].proc;
|
||||||
|
}
|
||||||
|
return handle_to_proc( (WNDPROC)handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a 16-bit thunk for an existing window proc */
|
||||||
|
static WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
|
||||||
|
{
|
||||||
|
static FARPROC16 relay;
|
||||||
|
WNDPROC16 ret = 0;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
EnterCriticalSection( &winproc_cs );
|
||||||
|
|
||||||
|
if (!thunk_array) /* allocate the array and its selector */
|
||||||
|
{
|
||||||
|
LDT_ENTRY entry;
|
||||||
|
|
||||||
|
if (!(thunk_selector = wine_ldt_alloc_entries(1))) goto done;
|
||||||
|
if (!(thunk_array = VirtualAlloc( NULL, MAX_THUNKS * sizeof(WINPROC_THUNK), MEM_COMMIT,
|
||||||
|
PAGE_EXECUTE_READWRITE ))) goto done;
|
||||||
|
wine_ldt_set_base( &entry, thunk_array );
|
||||||
|
wine_ldt_set_limit( &entry, MAX_THUNKS * sizeof(WINPROC_THUNK) - 1 );
|
||||||
|
wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
|
||||||
|
wine_ldt_set_entry( thunk_selector, &entry );
|
||||||
|
relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if it already exists */
|
||||||
|
for (i = 0; i < thunk_used; i++) if (thunk_array[i].proc == proc) break;
|
||||||
|
|
||||||
|
if (i == thunk_used) /* create a new one */
|
||||||
|
{
|
||||||
|
WINPROC_THUNK *thunk;
|
||||||
|
|
||||||
|
if (thunk_used >= MAX_THUNKS) goto done;
|
||||||
|
thunk = &thunk_array[thunk_used++];
|
||||||
|
thunk->popl_eax = 0x58; /* popl %eax */
|
||||||
|
thunk->pushl_func = 0x68; /* pushl $proc */
|
||||||
|
thunk->proc = proc;
|
||||||
|
thunk->pushl_eax = 0x50; /* pushl %eax */
|
||||||
|
thunk->ljmp = 0xea; /* ljmp relay*/
|
||||||
|
thunk->relay_offset = OFFSETOF(relay);
|
||||||
|
thunk->relay_sel = SELECTOROF(relay);
|
||||||
|
}
|
||||||
|
ret = (WNDPROC16)MAKESEGPTR( thunk_selector, i * sizeof(WINPROC_THUNK) );
|
||||||
|
done:
|
||||||
|
LeaveCriticalSection( &winproc_cs );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* __i386__ */
|
||||||
|
|
||||||
|
static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
|
||||||
|
{
|
||||||
|
return handle_to_proc( (WNDPROC)handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __i386__ */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
/* Some window procedures modify register they shouldn't, or are not
|
/* Some window procedures modify register they shouldn't, or are not
|
||||||
* properly declared stdcall; so we need a small assembly wrapper to
|
* properly declared stdcall; so we need a small assembly wrapper to
|
||||||
|
@ -495,8 +510,7 @@ WNDPROC16 WINPROC_GetProc16( WNDPROC proc, BOOL unicode )
|
||||||
if (ptr->type == WIN_PROC_16)
|
if (ptr->type == WIN_PROC_16)
|
||||||
return ptr->u.proc16;
|
return ptr->u.proc16;
|
||||||
else
|
else
|
||||||
return (WNDPROC16)MAKESEGPTR( get_winproc_selector(),
|
return alloc_win16_thunk( ptr );
|
||||||
(char *)&ptr->thunk - (char *)winproc_array );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue