Skip to content

Instantly share code, notes, and snippets.

@vaualbus
Created September 9, 2018 11:45
Show Gist options
  • Save vaualbus/4fb1e76e9a0f319534a745109b8c6078 to your computer and use it in GitHub Desktop.
Save vaualbus/4fb1e76e9a0f319534a745109b8c6078 to your computer and use it in GitHub Desktop.
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