Jacek Caban : atlthunk: Implement AtlThunk functions.
Alexandre Julliard
julliard at winehq.org
Tue Feb 19 15:29:33 CST 2019
Module: wine
Branch: master
Commit: 89ef868e5e25d236b3673dd6d3e7bd54013e3617
URL: https://source.winehq.org/git/wine.git/?a=commit;h=89ef868e5e25d236b3673dd6d3e7bd54013e3617
Author: Jacek Caban <jacek at codeweavers.com>
Date: Mon Feb 18 22:06:15 2019 +0100
atlthunk: Implement AtlThunk functions.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/atlthunk/atlthunk.c | 148 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 144 insertions(+), 4 deletions(-)
diff --git a/dlls/atlthunk/atlthunk.c b/dlls/atlthunk/atlthunk.c
index 79d0432..cd37b75 100644
--- a/dlls/atlthunk/atlthunk.c
+++ b/dlls/atlthunk/atlthunk.c
@@ -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__ */
More information about the wine-cvs
mailing list