Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
This file replace the msvc CRT and allow you to init static variables and TLS
#if _CRT_DISABLE
extern "C" int _fltused = 0x9875;
#define WIN32_LEAN_AND_MEAN
#include <stdint.h>
#include <limits.h>
#include <windows.h>
//#include <Windows.h>
#define ArrayCount(Name) (sizeof(Name)/(sizeof(Name[0]))
#define _CRTALLOC(x) __declspec(allocate(x))
#define nullptr 0
typedef int (__cdecl* _PIFV)(void);
typedef void (__cdecl* _PVFV)(void);
void __acrt_iob_func()
{
}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 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
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;
//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;
}
static void _crt_init_atexit_tables(void)
{
if(!ExitList)
{
MaxExitListEntries = 32;
ExitList = (_PVFV*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
MaxExitListEntries*sizeof(_PVFV));
}
}
static void _crt_clean_atexit_tables(void)
{
if(ExitList)
{
MaxExitListEntries = 0;
CurrentExitListIndex = 0;
HeapFree(GetProcessHeap(), 0, ExitList);
}
}
static void __cdecl _crt_thread_exit_func(void)
{
DeleteCriticalSection(&_Tss_mutex);
}
static int __cdecl _crt_thread_init()
{
InitializeCriticalSectionAndSpinCount(&_Tss_mutex, 4000);
InitializeConditionVariable(&_Tss_cv);
_crt_init_atexit_tables();
atexit(_crt_thread_exit_func);
return 0;
}
static _CRTALLOC(".CRT$XIC") _PIFV __scrt_initialize_tss_var = _crt_thread_init;
static _CRTALLOC(".CRT$XDA") _PVFV __xd_a = nullptr;
static _CRTALLOC(".CRT$XDZ") _PVFV __xd_z = nullptr;
static int
__crt_tls_exception_filter(unsigned long const Code)
{
//NOTE: handle C++ exception
if (Code == ('msc' | 0xE0000000))
{
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void WINAPI __crt_tls_init_callback(PVOID, DWORD Reason, LPVOID)
{
if(Reason != DLL_THREAD_ATTACH)
{
return;
}
{
for(_PVFV *Func = &__xd_a + 1; Func != &__xd_z; ++Func)
{
if(*Func)
{
(*Func)();
}
}
}
}
/*
* Define an initialized callback function pointer, so CRT startup code knows
* we have dynamically initialized __declspec(thread) variables that need to
* be initialized at process startup for the primary thread.
*/
extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = __crt_tls_init_callback;
/*
* Enter a callback function pointer into the .CRT$XL* array, which is the
* callback array pointed to by the IMAGE_TLS_DIRECTORY in the PE header, so
* the OS knows we want to be notified on each thread startup/shutdown.
*/
static _CRTALLOC(".CRT$XLC") PIMAGE_TLS_CALLBACK __xl_c = __crt_tls_init_callback;
//TODO: Thread Local Storage bullshit used by thread library....
// Still dows not working.....
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 = _Init_global_epoch;
}
_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();
}
extern "C" int
__cdecl _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
__cdecl _initterm (_PVFV * first, _PVFV * last)
{
for (_PVFV* it = first; it != last; ++it)
{
if (*it == nullptr)
continue;
(**it)();
}
}
extern "C" int
__cdecl atexit(_PVFV Func)
{
if(CurrentExitListIndex < MaxExitListEntries)
{
ExitList[CurrentExitListIndex++] = Func;
return 0;
}
return -1;
}
#pragma function(memset)
extern "C" void *memset(void *Dest, int Value, size_t Size)
{
unsigned char Val = *(unsigned char*)&Value;
unsigned char *At = (unsigned char*)Dest;
while(Size--)
{
*At++ = Val;
}
return Dest;
}
#pragma function(memcpy)
extern "C" void *memcpy(void *Dest, const void *Source, size_t Size)
{
char *D = (char*)Dest;
const char *S = (char*)Source;
while(Size--)
{
*D++ = *S++;
}
return Dest;
}
#pragma function(memcmp)
extern "C" int memcmp(const void *A, const void *B, size_t Count)
{
register const unsigned char *s1 = (const unsigned char*)A;
register const unsigned char *s2 = (const unsigned char*)B;
while (Count-- > 0)
{
if (*s1++ != *s2++)
{
return s1[-1] < s2[-1] ? -1 : 1;
}
}
return 0;
}
void __stdcall __ehvec_ctor(
void* ptr, // Pointer to array to destruct
size_t size, // Size of each element (including padding)
size_t count, // Number of elements in the array
void (__stdcall *constructor)(void*), // Constructor to call
void (__stdcall *destructor)(void*))
{
size_t i{0};
bool Success{false};
{
for (; i != count; ++i)
{
constructor(ptr);
ptr = static_cast<char*>(ptr) + size;
}
Success = true;
}
}
void __stdcall __ehvec_dtor(
void* ptr,
size_t size,
size_t count,
void (__stdcall *destructor)(void*))
{
int Success = 0;
// Advance pointer past end of array
ptr = (char*)(ptr) + size * count;
{
// Destruct elements
while (count-- > 0)
{
ptr = (char*)(ptr) - size;
destructor(ptr);
}
Success = 1;
}
}
static void Win32CRTCall(_PVFV* a, _PVFV* b)
{
while (a != b)
{
if (*a)
{
(**a)();
}
++a;
}
}
void InitCRTEnviroment(void)
{
_crt_init_atexit_tables();
_initterm_e(__xi_a, __xi_z);
_initterm(__xc_a, __xc_z);
}
void ExitCRTEnviroment(void)
{
if(CurrentExitListIndex)
{
_initterm(ExitList, ExitList + CurrentExitListIndex);
}
_crt_clean_atexit_tables();
Win32CRTCall(__xp_a, __xp_z);
Win32CRTCall(__xt_a, __xt_z);
}
extern "C"
{
DWORD __CxxFrameHandler3(PEXCEPTION_RECORD rec, EXCEPTION_REGISTRATION_RECORD* ExceptionRegistrationFrame,
CONTEXT *Context, EXCEPTION_REGISTRATION_RECORD** Record)
{
return 0;
}
}
#else
void InitCRTEnviroment(void)
{
}
void ExitCRTEnviroment(void)
{
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.