我在之前的博客里并未提及过Tls的底层初始化,现在好好来谈谈。
首先我们要知道Tls的初始化是在入口之前。先从一开始的LdrInitializeThunk说起,在调用LdrPEStartup时,其在修复完导入表后,调用了一次LdrpInitializeTlsForProccess,我们看看他是怎样处理的。
static NTSTATUS
LdrpInitializeTlsForProccess(VOID)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY Module;
PIMAGE_TLS_DIRECTORY TlsDirectory;
PTLS_DATA TlsData;
ULONG Size;
DPRINT("LdrpInitializeTlsForProccess() called for %wZn", &ExeModule->BaseDllName);
if (LdrpTlsCount > 0)
{
LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
0,
LdrpTlsCount * sizeof(TLS_DATA));//分配了一个容纳所有Tls变量的空间,基于线程
if (LdrpTlsArray == NULL)
{
DPRINT1("Failed to allocate global tls data\n");
return STATUS_NO_MEMORY;
}
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
while (Entry != ModuleListHead)//以装载顺序遍历
{
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&
Module->TlsIndex != 0xFFFF)
{
TlsDirectory = (PIMAGE_TLS_DIRECTORY)//获得TLS目录表
RtlImageDirectoryEntryToData(Module->DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_TLS,
&Size);
ASSERT(Module->TlsIndex < LdrpTlsCount);
TlsData = &LdrpTlsArray[Module->TlsIndex];//TlsData存放的是记录着该模块Tls信息的指针,其index在TlsIndex里
TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;//对该模块的信息进行填充
TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
TlsData