summaryrefslogtreecommitdiffstats
path: root/src/kWorker/kWorkerTlsXxxK.c
blob: 829a66e9576283668c474530b9cc3e057e29f87d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* $Id: kWorkerTlsXxxK.c 3366 2020-06-09 23:53:39Z bird $ */
/** @file
 * kWorkerTlsXxxK - Loader TLS allocation hack DLL.
 */

/*
 * Copyright (c) 2017 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
 *
 * This file is part of kBuild.
 *
 * kBuild is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * kBuild is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
 *
 */


/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/
#include <windows.h>


/*********************************************************************************************************************************
*   Structures and Typedefs                                                                                                      *
*********************************************************************************************************************************/
typedef void KWLDRTLSCALLBACK(void *hDll, DWORD dwReason, void *pvContext, void *pvWorkerModule);
typedef KWLDRTLSCALLBACK *PKWLDRTLSCALLBACK;
typedef PKWLDRTLSCALLBACK KWLDRTLSALLOCATIONHOOK(void *hDll, ULONG idxTls, char *pabInitData, void **ppvWorkerModule);


/*********************************************************************************************************************************
*   Internal Functions                                                                                                           *
*********************************************************************************************************************************/
__declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext);


/*********************************************************************************************************************************
*   Global Variables                                                                                                             *
*********************************************************************************************************************************/
/** The TLS pointer array. The 2nd entry is NULL and serve to terminate the array.
 * The first entry can be used by kWorker if it needs to. */
__declspec(dllexport) PIMAGE_TLS_CALLBACK   g_apfnTlsCallbacks[2]   = { DummyTlsCallback, NULL };

/**
 * The TLS index.
 */
__declspec(dllexport) ULONG                 g_idxTls                = ~(ULONG)0;

/**
 * Callback context.
 */
__declspec(dllexport) void                 *g_pvWorkerModule        = NULL;

/**
 * Regular callback method (returned by kwLdrTlsAllocationHook).
 */
__declspec(dllexport) PKWLDRTLSCALLBACK     g_pfnWorkerCallback     = NULL;



/**
 * Initialization data.
 * kWorker will copy the init data of the target DLL here.
 */
static char g_abInitData[TLS_SIZE] = {0};

/**
 * The TLS directory entry.  Not possible to get more than one from the linker
 * and probably also the loader doesn't want more than one anyway.
 */
#pragma section(".rdata$T", long, read)
__declspec(allocate(".rdata$T")) const IMAGE_TLS_DIRECTORY _tls_used =
{
    (ULONG_PTR)&g_abInitData,
    (ULONG_PTR)&g_abInitData + sizeof(g_abInitData),
    (ULONG_PTR)&g_idxTls,
    (ULONG_PTR)&g_apfnTlsCallbacks,
    0, /* This SizeOfZeroFill bugger doesn't work on w10/amd64 from what I can tell! */
    IMAGE_SCN_ALIGN_32BYTES
};


/**
 * Just a dummy callback function in case the allocation hook gambit fails below
 * (see KWLDRTLSCALLBACK).
 */
static void DummyWorkerCallback(void *hDll, DWORD dwReason, void *pvContext, void *pvWorkerModule)
{
    (void)hDll; (void)dwReason; (void)pvContext; (void)pvWorkerModule;
}


/*
 * This is just a dummy TLS callback function.
 * We'll be replacing g_apfnTlsCallbacks[0] from kWorker.c after loading it.
 *
 * Note! W10 doesn't seem to want to process the TLS directory if the DLL
 *       doesn't have any imports (to snap).
 */
__declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext)
{
    if (g_pfnWorkerCallback)
        g_pfnWorkerCallback(hDll, dwReason, pvContext, g_pvWorkerModule);
    else
    {
        g_pfnWorkerCallback = DummyWorkerCallback;
        if (dwReason == DLL_PROCESS_ATTACH)
        {
            HMODULE hModExe = GetModuleHandleW(NULL);
            KWLDRTLSALLOCATIONHOOK *pfnHook = (KWLDRTLSALLOCATIONHOOK *)GetProcAddress(hModExe, "kwLdrTlsAllocationHook");
            if (pfnHook)
                g_pfnWorkerCallback = pfnHook(hDll, g_idxTls, g_abInitData, &g_pvWorkerModule);
            else
                __debugbreak();
        }
    }
}


/*
 * Dummy DLL entry point to avoid dragging in unnecessary CRT stuff. kWorkerTls1K!_tls_index
 */
BOOL __stdcall DummyDllEntry(void *hDll, DWORD dwReason, void *pvContext)
{
    (void)hDll; (void)dwReason; (void)pvContext;
    return TRUE;
}