Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/atlthunk/atlthunk.c
4389 views
1
/*
2
* Copyright 2019 Jacek Caban for CodeWeavers
3
*
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
8
*
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
13
*
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17
*/
18
19
#include "windows.h"
20
#include "atlthunk.h"
21
#include "wine/debug.h"
22
23
WINE_DEFAULT_DEBUG_CHANNEL(atlthunk);
24
25
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
26
27
struct AtlThunkData_t {
28
struct thunk_pool *pool;
29
WNDPROC proc;
30
SIZE_T arg;
31
};
32
33
/* Thunk replaces the first argument and jumps to provided proc. */
34
#pragma pack(push,1)
35
struct thunk_code
36
{
37
#if defined(__x86_64__)
38
BYTE mov_rip_rcx[3]; /* mov mov_offset(%rip), %rcx */
39
DWORD mov_offset;
40
WORD jmp_rip; /* jmp *jmp_offset(%rip) */
41
DWORD jmp_offset;
42
#elif defined(__i386__)
43
BYTE mov_data_addr_eax; /* movl data_addr, %eax */
44
DWORD data_addr;
45
DWORD mov_eax_esp; /* movl %eax, 4(%esp) */
46
WORD jmp;
47
DWORD jmp_addr; /* jmp *jmp_addr */
48
#elif defined(__aarch64__)
49
DWORD ldr_x0; /* ldr x0,data_addr */
50
DWORD ldr_x16; /* ldr x16,proc_addr */
51
DWORD br_x16; /* br x16 */
52
DWORD pad;
53
#endif
54
};
55
#pragma pack(pop)
56
57
#define THUNK_POOL_SIZE (4096 / sizeof(struct thunk_code))
58
59
struct thunk_pool
60
{
61
struct thunk_code thunks[THUNK_POOL_SIZE];
62
LONG first_free;
63
LONG free_count;
64
AtlThunkData_t data[THUNK_POOL_SIZE];
65
};
66
67
C_ASSERT(FIELD_OFFSET(struct thunk_pool, first_free) == 4096);
68
69
static struct thunk_pool *alloc_thunk_pool(void)
70
{
71
struct thunk_pool *thunks;
72
DWORD old_protect;
73
unsigned i;
74
75
if (!(thunks = VirtualAlloc(NULL, sizeof(*thunks), MEM_COMMIT, PAGE_READWRITE)))
76
return NULL;
77
78
for (i = 0; i < ARRAY_SIZE(thunks->thunks); i++)
79
{
80
struct thunk_code *thunk = &thunks->thunks[i];
81
#if defined(__x86_64__)
82
thunk->mov_rip_rcx[0] = 0x48; /* mov mov_offset(%rip), %rcx */
83
thunk->mov_rip_rcx[1] = 0x8b;
84
thunk->mov_rip_rcx[2] = 0x0d;
85
thunk->mov_offset = (const BYTE *)&thunks->data[i].arg - (const BYTE *)(&thunk->mov_offset + 1);
86
thunk->jmp_rip = 0x25ff; /* jmp *jmp_offset(%rip) */
87
thunk->jmp_offset = (const BYTE *)&thunks->data[i].proc - (const BYTE *)(&thunk->jmp_offset + 1);
88
#elif defined(__i386__)
89
thunk->mov_data_addr_eax = 0xa1; /* movl data_addr, %eax */
90
thunk->data_addr = (DWORD)&thunks->data[i].arg;
91
thunk->mov_eax_esp = 0x04244489; /* movl %eax, 4(%esp) */
92
thunk->jmp = 0x25ff; /* jmp *jmp_addr */
93
thunk->jmp_addr = (DWORD)&thunks->data[i].proc;
94
#elif defined(__aarch64__)
95
thunk->ldr_x0 = 0x58000000 | (((DWORD *)&thunks->data[i].arg - &thunk->ldr_x0) << 5);
96
thunk->ldr_x16 = 0x58000010 | (((DWORD *)&thunks->data[i].proc - &thunk->ldr_x16) << 5);
97
thunk->br_x16 = 0xd61f0200;
98
#endif
99
}
100
VirtualProtect(thunks->thunks, FIELD_OFFSET(struct thunk_pool, first_free), PAGE_EXECUTE_READ, &old_protect);
101
thunks->first_free = 0;
102
thunks->free_count = 0;
103
return thunks;
104
}
105
106
static struct thunk_pool *current_pool;
107
108
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
109
{
110
switch (reason)
111
{
112
case DLL_PROCESS_ATTACH:
113
DisableThreadLibraryCalls(instance);
114
break;
115
case DLL_PROCESS_DETACH:
116
if (reserved) break;
117
if (current_pool && current_pool->free_count == current_pool->first_free)
118
VirtualFree(current_pool, sizeof(*current_pool), MEM_RELEASE);
119
break;
120
}
121
return TRUE;
122
}
123
124
static CRITICAL_SECTION thunk_alloc_cs;
125
static CRITICAL_SECTION_DEBUG thunk_alloc_cs_debug = {
126
0, 0, &thunk_alloc_cs,
127
{ &thunk_alloc_cs_debug.ProcessLocksList,
128
&thunk_alloc_cs_debug.ProcessLocksList },
129
0, 0, { (DWORD_PTR)(__FILE__ ": thunk_alloc_cs") }
130
};
131
static CRITICAL_SECTION thunk_alloc_cs = { &thunk_alloc_cs_debug, -1, 0, 0, 0, 0 };
132
133
AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
134
{
135
AtlThunkData_t *thunk = NULL;
136
137
EnterCriticalSection(&thunk_alloc_cs);
138
139
if (!current_pool) current_pool = alloc_thunk_pool();
140
if (current_pool)
141
{
142
thunk = &current_pool->data[current_pool->first_free];
143
thunk->pool = current_pool;
144
thunk->proc = NULL;
145
thunk->arg = 0;
146
if (++current_pool->first_free == ARRAY_SIZE(current_pool->data))
147
current_pool = NULL;
148
}
149
150
LeaveCriticalSection(&thunk_alloc_cs);
151
return thunk;
152
}
153
154
WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
155
{
156
WNDPROC code = (WNDPROC)&thunk->pool->thunks[thunk - thunk->pool->data];
157
TRACE("(%p) -> %p\n", thunk, code);
158
return code;
159
}
160
161
void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
162
{
163
if (InterlockedIncrement(&thunk->pool->free_count) == ARRAY_SIZE(thunk->pool->thunks))
164
VirtualFree(thunk->pool, sizeof(*thunk->pool), MEM_RELEASE);
165
}
166
167
void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
168
{
169
thunk->proc = proc;
170
thunk->arg = arg;
171
}
172
173
#else /* __i386__ || __x86_64__ || __aarch64__ */
174
175
AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
176
{
177
FIXME("Unsupported architecture.\n");
178
return NULL;
179
}
180
181
WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
182
{
183
return NULL;
184
}
185
186
void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
187
{
188
}
189
190
void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
191
{
192
}
193
194
#endif /* __i386__ || __x86_64__ || __aarch64__ */
195
196