atlthunk: Implement AtlThunk functions.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3fe02210a9
commit
89ef868e5e
|
@ -22,24 +22,164 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(atlthunk);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
struct AtlThunkData_t {
|
||||
struct thunk_pool *pool;
|
||||
WNDPROC proc;
|
||||
SIZE_T arg;
|
||||
};
|
||||
|
||||
/* Thunk replaces the first argument and jumps to provided proc. */
|
||||
#include "pshpack1.h"
|
||||
struct thunk_code
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
BYTE mov_rip_rcx[3]; /* mov mov_offset(%rip), %rcx */
|
||||
DWORD mov_offset;
|
||||
WORD jmp_rip; /* jmp *jmp_offset(%rip) */
|
||||
DWORD jmp_offset;
|
||||
#elif defined(__i386__)
|
||||
BYTE mov_data_addr_eax; /* movl data_addr, %eax */
|
||||
DWORD data_addr;
|
||||
DWORD mov_eax_esp; /* movl %eax, 4(%esp) */
|
||||
WORD jmp;
|
||||
DWORD jmp_addr; /* jmp *jmp_addr */
|
||||
#endif
|
||||
};
|
||||
#include "poppack.h"
|
||||
|
||||
#define THUNK_POOL_SIZE (4096 / sizeof(struct thunk_code))
|
||||
|
||||
struct thunk_pool
|
||||
{
|
||||
struct thunk_code thunks[THUNK_POOL_SIZE];
|
||||
LONG first_free;
|
||||
LONG free_count;
|
||||
AtlThunkData_t data[THUNK_POOL_SIZE];
|
||||
};
|
||||
|
||||
C_ASSERT(FIELD_OFFSET(struct thunk_pool, first_free) == 4096);
|
||||
|
||||
static struct thunk_pool *alloc_thunk_pool(void)
|
||||
{
|
||||
struct thunk_pool *thunks;
|
||||
DWORD old_protect;
|
||||
unsigned i;
|
||||
|
||||
if (!(thunks = VirtualAlloc(NULL, sizeof(*thunks), MEM_COMMIT, PAGE_READWRITE)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(thunks->thunks); i++)
|
||||
{
|
||||
struct thunk_code *thunk = &thunks->thunks[i];
|
||||
#if defined(__x86_64__)
|
||||
thunk->mov_rip_rcx[0] = 0x48; /* mov mov_offset(%rip), %rcx */
|
||||
thunk->mov_rip_rcx[1] = 0x8b;
|
||||
thunk->mov_rip_rcx[2] = 0x0d;
|
||||
thunk->mov_offset = (const BYTE *)&thunks->data[i].arg - (const BYTE *)(&thunk->mov_offset + 1);
|
||||
thunk->jmp_rip = 0x25ff; /* jmp *jmp_offset(%rip) */
|
||||
thunk->jmp_offset = (const BYTE *)&thunks->data[i].proc - (const BYTE *)(&thunk->jmp_offset + 1);
|
||||
#elif defined(__i386__)
|
||||
thunk->mov_data_addr_eax = 0xa1; /* movl data_addr, %eax */
|
||||
thunk->data_addr = (DWORD)&thunks->data[i].arg;
|
||||
thunk->mov_eax_esp = 0x04244489; /* movl %eax, 4(%esp) */
|
||||
thunk->jmp = 0x25ff; /* jmp *jmp_addr */
|
||||
thunk->jmp_addr = (DWORD)&thunks->data[i].proc;
|
||||
#endif
|
||||
}
|
||||
VirtualProtect(thunks->thunks, FIELD_OFFSET(struct thunk_pool, first_free), PAGE_EXECUTE_READ, &old_protect);
|
||||
thunks->first_free = 0;
|
||||
thunks->free_count = 0;
|
||||
return thunks;
|
||||
}
|
||||
|
||||
static struct thunk_pool *current_pool;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(instance);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (reserved) break;
|
||||
if (current_pool && current_pool->free_count == current_pool->first_free)
|
||||
VirtualFree(current_pool, sizeof(*current_pool), MEM_RELEASE);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static CRITICAL_SECTION thunk_alloc_cs;
|
||||
static CRITICAL_SECTION_DEBUG thunk_alloc_cs_debug = {
|
||||
0, 0, &thunk_alloc_cs,
|
||||
{ &thunk_alloc_cs_debug.ProcessLocksList,
|
||||
&thunk_alloc_cs_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": thunk_alloc_cs") }
|
||||
};
|
||||
static CRITICAL_SECTION thunk_alloc_cs = { &thunk_alloc_cs_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
|
||||
{
|
||||
FIXME("\n");
|
||||
AtlThunkData_t *thunk = NULL;
|
||||
|
||||
EnterCriticalSection(&thunk_alloc_cs);
|
||||
|
||||
if (!current_pool) current_pool = alloc_thunk_pool();
|
||||
if (current_pool)
|
||||
{
|
||||
thunk = ¤t_pool->data[current_pool->first_free];
|
||||
thunk->pool = current_pool;
|
||||
thunk->proc = NULL;
|
||||
thunk->arg = 0;
|
||||
if (++current_pool->first_free == ARRAY_SIZE(current_pool->data))
|
||||
current_pool = NULL;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&thunk_alloc_cs);
|
||||
return thunk;
|
||||
}
|
||||
|
||||
WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
|
||||
{
|
||||
WNDPROC code = (WNDPROC)&thunk->pool->thunks[thunk - thunk->pool->data];
|
||||
TRACE("(%p) -> %p\n", thunk, code);
|
||||
return code;
|
||||
}
|
||||
|
||||
void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
|
||||
{
|
||||
if (InterlockedIncrement(&thunk->pool->free_count) == ARRAY_SIZE(thunk->pool->thunks))
|
||||
VirtualFree(thunk->pool, sizeof(*thunk->pool), MEM_RELEASE);
|
||||
}
|
||||
|
||||
void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
|
||||
{
|
||||
thunk->proc = proc;
|
||||
thunk->arg = arg;
|
||||
}
|
||||
|
||||
#else /* __i386__ || __x86_64__ */
|
||||
|
||||
AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
|
||||
{
|
||||
FIXME("Unsupported architecture.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
|
||||
{
|
||||
FIXME("(%p)\n", thunk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
|
||||
{
|
||||
FIXME("(%p)\n", thunk);
|
||||
}
|
||||
|
||||
void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
|
||||
{
|
||||
FIXME("(%p %p %lx)\n", thunk, proc, arg);
|
||||
}
|
||||
|
||||
#endif /* __i386__ || __x86_64__ */
|
||||
|
|
Loading…
Reference in New Issue