This code will initialize all the static variables and set up the basic TLS context to allow static variables in function to work
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#define _CRTALLOC(x) __declspec(allocate(x)) | |
#define nullptr 0 | |
#define ArrayCount(Name) (sizeof(Name)/(sizeof(Name[0])) | |
void __acrt_iob_func() | |
{ | |
} | |
typedef int (__cdecl* _PIFV)(void); | |
typedef void (__cdecl* _PVFV)(void); | |
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
// | |
// Section Attributes | |
// | |
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
#pragma section(".CRT$XCA", long, read) // First C++ Initializer | |
#pragma section(".CRT$XCAA", long, read) // Startup C++ Initializer | |
#pragma section(".CRT$XCZ", long, read) // Last C++ Initializer | |
#pragma section(".CRT$XDA", long, read) // First Dynamic TLS Initializer | |
#pragma section(".CRT$XDZ", long, read) // Last Dynamic TLS Initializer | |
#pragma section(".CRT$XIA", long, read) // First C Initializer | |
#pragma section(".CRT$XIAA", long, read) // Startup C Initializer | |
#pragma section(".CRT$XIAB", long, read) // PGO C Initializer | |
#pragma section(".CRT$XIAC", long, read) // Post-PGO C Initializer | |
#pragma section(".CRT$XIC", long, read) // CRT C Initializers | |
#pragma section(".CRT$XIYA", long, read) // VCCorLib Threading Model Initializer | |
#pragma section(".CRT$XIYAA", long, read) // XAML Designer Threading Model Override Initializer | |
#pragma section(".CRT$XIYB", long, read) // VCCorLib Main Initializer | |
#pragma section(".CRT$XIZ", long, read) // Last C Initializer | |
#pragma section(".CRT$XLA", long, read) // First Loader TLS Callback | |
#pragma section(".CRT$XLC", long, read) // CRT TLS Constructor | |
#pragma section(".CRT$XLD", long, read) // CRT TLS Terminator | |
#pragma section(".CRT$XLZ", long, read) // Last Loader TLS Callback | |
#pragma section(".CRT$XPA", long, read) // First Pre-Terminator | |
#pragma section(".CRT$XPB", long, read) // CRT ConcRT Pre-Terminator | |
#pragma section(".CRT$XPX", long, read) // CRT Pre-Terminators | |
#pragma section(".CRT$XPXA", long, read) // CRT stdio Pre-Terminator | |
#pragma section(".CRT$XPZ", long, read) // Last Pre-Terminator | |
#pragma section(".CRT$XTA", long, read) // First Terminator | |
#pragma section(".CRT$XTZ", long, read) // Last Terminator | |
#pragma section(".CRTMA$XCA", long, read) // First Managed C++ Initializer | |
#pragma section(".CRTMA$XCZ", long, read) // Last Managed C++ Initializer | |
#pragma section(".CRTVT$XCA", long, read) // First Managed VTable Initializer | |
#pragma section(".CRTVT$XCZ", long, read) // Last Managed VTable Initializer | |
#pragma section(".rdata$T", long, read) | |
#pragma section(".rtc$IAA", long, read) // First RTC Initializer | |
#pragma section(".rtc$IZZ", long, read) // Last RTC Initializer | |
#pragma section(".rtc$TAA", long, read) // First RTC Terminator | |
#pragma section(".rtc$TZZ", long, read) // Last RTC Terminator | |
#define _CRTALLOC(x) __declspec(allocate(x)) | |
extern "C" _CRTALLOC(".CRT$XIA") _PIFV __xi_a[] = { nullptr }; // C initializers (first) | |
extern "C" _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[] = { nullptr }; // C initializers (last) | |
extern "C" _CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { nullptr }; // C++ initializers (first) | |
extern "C" _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { nullptr }; // C++ initializers (last) | |
extern "C" _CRTALLOC(".CRT$XPA") _PVFV __xp_a[] = { nullptr }; // C pre-terminators (first) | |
extern "C" _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[] = { nullptr }; // C pre-terminators (last) | |
extern "C" _CRTALLOC(".CRT$XTA") _PVFV __xt_a[] = { nullptr }; // C terminators (first) | |
extern "C" _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[] = { nullptr }; // C terminators (last) | |
#pragma comment(linker, "/merge:.CRT=.rdata") | |
int const StaticNotInitialized = 0; | |
int const StaticInitialized = -1; | |
int const EpochStart = INT_MIN; | |
DWORD const XpTimeout = 100; | |
static _PVFV * ExitList; | |
static unsigned MaxExitListEntries; | |
static unsigned CurrentExitListIndex; | |
CRITICAL_SECTION _Tss_mutex; | |
CONDITION_VARIABLE _Tss_cv; | |
void Win32InitThreadLocale() | |
{ | |
InitializeCriticalSectionAndSpinCount(&_Tss_mutex, 4000); | |
InitializeConditionVariable(&_Tss_cv); | |
} | |
static void __cdecl _thread_init_statics_end(void) | |
{ | |
DeleteCriticalSection(&_Tss_mutex); | |
} | |
int __cdecl _thread_init_statics() | |
{ | |
MaxExitListEntries = 32; | |
ExitList = (_PVFV*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | |
MaxExitListEntries*sizeof(_PVFV)); | |
Win32InitThreadLocale(); | |
atexit(_thread_init_statics_end); | |
return 0; | |
} | |
_CRTALLOC(".CRT$XIC") static _PIFV __scrt_initialize_tss_var = _thread_init_statics; | |
//NOTE: TLS Bullshit | |
extern "C" | |
{ | |
ULONG _tls_index = 0; | |
#pragma data_seg(".tls") | |
_CRTALLOC(".tls") | |
char _tls_start = 0; | |
#pragma data_seg(".tls$ZZZ") | |
_CRTALLOC(".tls$ZZZ") | |
char _tls_end = 0; | |
#pragma data_seg() | |
//NOTE: Start of TLS callback generated by os loader code | |
_CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0; | |
//NOTE: Terminator of TLS callback array | |
_CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0; | |
//NOTE: TLS array.. | |
_CRTALLOC(".rdata$T") | |
extern const IMAGE_TLS_DIRECTORY64 _tls_used = | |
{ | |
(ULONGLONG) &_tls_start, | |
(ULONGLONG) &_tls_end, | |
(ULONGLONG) &_tls_index, | |
(ULONGLONG) (&__xl_a + 1), | |
(ULONG)0, | |
(LONG)0 | |
}; | |
} | |
extern "C" | |
{ | |
int _Init_global_epoch = EpochStart; | |
__declspec(thread) int _Init_thread_epoch = EpochStart; | |
} | |
//TODO: Thread Local Storage bullshit used by thread library.... | |
extern "C" void __cdecl _Init_thread_lock(void) | |
{ | |
EnterCriticalSection(&_Tss_mutex); | |
} | |
extern "C" void __cdecl _Init_thread_unlock(void) | |
{ | |
LeaveCriticalSection(&_Tss_mutex); | |
} | |
extern "C" void __cdecl _Init_thread_wait(DWORD const TimeOut) | |
{ | |
SleepConditionVariableCS(&_Tss_cv, &_Tss_mutex, TimeOut); | |
_Init_thread_lock(); | |
WaitForSingleObjectEx(0, TimeOut, FALSE); | |
_Init_thread_unlock(); | |
} | |
extern "C" void __cdecl _Init_thread_notify(void) | |
{ | |
WakeAllConditionVariable(&_Tss_cv); | |
} | |
extern "C" void __cdecl _Init_thread_header(int* const Static) | |
{ | |
_Init_thread_lock(); | |
if(*Static == StaticNotInitialized) | |
{ | |
*Static = StaticInitialized; | |
} | |
else | |
{ | |
//NOTE: Fix for WinXP.... | |
_Init_thread_wait(XpTimeout); | |
while(*Static == StaticInitialized) | |
{ | |
if(*Static == StaticNotInitialized) | |
{ | |
*Static = StaticInitialized; | |
_Init_thread_unlock(); | |
} | |
} | |
_Init_thread_epoch = _Init_global_epoch; | |
} | |
_Init_thread_unlock(); | |
} | |
extern "C" void __cdecl _Init_thread_footer(int* const Static) | |
{ | |
_Init_thread_lock(); | |
{ | |
++_Init_global_epoch; | |
*Static = StaticNotInitialized; | |
} | |
_Init_thread_unlock(); | |
_Init_thread_notify(); | |
} | |
extern "C" void __cdecl _Init_thread_abort(int* const Static) | |
{ | |
_Init_thread_lock(); | |
{ | |
*Static = StaticNotInitialized; | |
} | |
_Init_thread_unlock(); | |
_Init_thread_notify(); | |
} | |
static void Win32CRTCall(_PVFV* a, _PVFV* b) | |
{ | |
while (a != b) | |
{ | |
if (*a) | |
{ | |
(**a)(); | |
} | |
++a; | |
} | |
} | |
extern "C" int _initterm_e (_PIFV * first, _PIFV * last) | |
{ | |
for (_PIFV* it = first; it != last; ++it) | |
{ | |
if (*it == nullptr) | |
continue; | |
int const result = (**it)(); | |
if (result != 0) | |
return result; | |
} | |
return 0; | |
} | |
extern "C" void _initterm (_PVFV * first, _PVFV * last) | |
{ | |
for (_PVFV* it = first; it != last; ++it) | |
{ | |
if (*it == nullptr) | |
continue; | |
(**it)(); | |
} | |
} | |
extern "C" int atexit(_PVFV Func) | |
{ | |
if(CurrentExitListIndex < MaxExitListEntries) | |
{ | |
ExitList[CurrentExitListIndex++] = Func; | |
return 0; | |
} | |
return -1; | |
} | |
void InitCRTEnviroment(void) | |
{ | |
_initterm_e(__xi_a, __xi_z); | |
_initterm(__xc_a, __xc_z); | |
} | |
void ExitCRTEnviroment(void) | |
{ | |
if(CurrentExitListIndex) | |
{ | |
_initterm(ExitList, ExitList + CurrentExitListIndex); | |
} | |
HeapFree(GetProcessHeap(), 0, ExitList); | |
Win32CRTCall(__xp_a, __xp_z); | |
Win32CRTCall(__xt_a, __xt_z); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment