{"id":186,"date":"2007-10-26T07:00:42","date_gmt":"2007-10-26T12:00:42","guid":{"rendered":"http:\/\/www.nynaeve.net\/?p=186"},"modified":"2019-12-13T17:45:34","modified_gmt":"2019-12-13T22:45:34","slug":"thread-local-storage-part-5-loader-support-for-__declspecthread-variables-process-initialization-time","status":"publish","type":"post","link":"http:\/\/www.nynaeve.net\/?p=186","title":{"rendered":"Thread Local Storage, part 5: Loader support for __declspec(thread) variables (process initialization time)"},"content":{"rendered":"<p><a title=\"Thread Local Storage, part 4: Accessing __declspec(thread) data\" href=\"http:\/\/www.nynaeve.net\/?p=185\">Last time<\/a>, I described the mechanism by which the compiler and linker generate code to access a variable that has been instanced per-thread via the <em>__declspec(thread)<\/em> extended storage class.  Although the compiler and linker have essentially &#8220;set the stage&#8221; with respect to implicit TLS at this point, the loader is the component that &#8220;fills in the dots&#8221; and supplies the necessary run-time infrastructure to allow everything to operate.<\/p>\n<p>Specifically, the loader is responsible for managing the allocation of per-module TLS index values, the allocation and management of the memory for the <em>ThreadLocalStoragePointer<\/em> array referred to by the TEB of every thread.  Additionally, the loader is also responsible for managing the memory for each module&#8217;s thread-instanced (that is, <em>__declspec(thread)<\/em>-decorated) variables.<\/p>\n<p>The loader&#8217;s TLS-related allocation and management duties can conceptually be split up into four distinct areas (<em>Note that this represents the Windows Server 2003 and earlier view of things; I will go over some of the changes that Windows Vista makes this this model in a future posting in the TLS series.<\/em>):<\/p>\n<ol>\n<li>At process initialization time, allocate <em>_tls_index<\/em> values, determine the extent of memory required for each module&#8217;s TLS block, and call TLS and DLL initializers (in that order).<\/li>\n<li>At thread initialization time, allocate and initialize TLS memory blocks for each module utilizing TLS, allocate the <em>ThreadLocalStoragePointer<\/em> array for the current thread, and link the TLS memory blocks in to the <em>ThreadLocalStoragePointer<\/em> array.  Additionally, TLS initializers and then DLL initializers (in that order) are invoked for the current thread.\n<li>At thread deinitialization time, call TLS deinitializers and then DLL deinitializers (in that order), and release the current thread&#8217;s TLS memory blocks for each module using TLS, and release the <em>ThreadLocalStoragePointer<\/em> array.<\/li>\n<li>At process deinitialization time, call TLS and DLL initializers (in that order).<\/li>\n<\/ol>\n<p>Of course, the loader performs a number of other tasks when these events occur; this is simply a list of those that have some bearing on TLS support.<\/p>\n<p>Most of these operations are fairly straightforward, with the arguable exception of process initialization.  Process initialization of TLS is primarily handled in two subroutines inside ntdll, <em>LdrpInitializeTls<\/em> and <em>LdrpAllocateTls<\/em>.<\/p>\n<p><em>LdrpInitializeTls<\/em> is invoked during process initialization after all DLLs have been loaded, but before any initializer (or TLS) routines have been called.  It essentially walks the loaded module list and sums the length of TLS data for each module that contains a valid TLS directory.  For each module that contains TLS, a data structure is allocated that contains the length of the module&#8217;s TLS data and the TLS index that has been assigned to that module.  (The <em>TlsIndex<\/em> field in the <em>LDR_DATA_TABLE_ENTRY<\/em> structure appears to be unused except as a flag that the module has TLS (being always set to -1), at least as far back as Windows XP.  It is worth mentioning that the <a title=\"wine\/dlls\/ntdll\/loader.c\" href=\"http:\/\/source.winehq.org\/source\/dlls\/ntdll\/loader.c#L770\">WINE implementation<\/a> of implicit TLS incorrectly uses <em>TlsIndex<\/em> as the real module TLS index, so it may be unreliable to assume that it is always -1 if you care about working on WINE.)<\/p>\n<p>Modules that use implicit TLS and which are present at initialization time are additionally marked as pinned in memory for the lifetime of the process by <em>LdrpInitializeProcess<\/em> (the <em>LoadCount<\/em> of any such module is fixed to 0xFFFF).  In practice, this is typically unlikely to matter, as for such modules to be present at process initialization time, they must also by definition static linked by either the main process image or a dependency of the main process image.<\/p>\n<p>After <em>LdrpInitializeTls<\/em> has determined which modules use TLS in the current process and has assigned those modules TLS index values, <em>LdrpAllocateTls<\/em> is called to allocate and initialize module TLS values for the initial thread.<\/p>\n<p>At this point, process initialization continues, eventually resulting in TLS initializers and then DLL initializers (<em>DllMain<\/em>) being called for loaded modules.  (<em>Note that the main process image can have one or more TLS callbacks, even though it cannot have a DLL initializer routine.<\/em>)<\/p>\n<p>One interesting fact about TLS initializers is that they are always called <em>before<\/em> DLL initializers for their corresponding DLL.  (The process occurs in sequence, such that DLL A&#8217;s TLS and DLL initializers are called, then DLL B&#8217;s TLS and DLL initializers, and so forth.)  This means that TLS initializers need to be careful about making, say, CRT calls (as the C runtime is initialized before the user&#8217;s <em>DllMain<\/em> routine is called, by the actual DLL initializer entrypoint, such that the CRT will not be initialized when a TLS initializer for the module is invoked).  This can be dangerous, as global objects will not have been constructed yet; the module will be in a completely uninitialized state except that imports have been snapped.<\/p>\n<p>Another point worth mentioning about the loader&#8217;s TLS support is that contrary to the <a title=\"Microsoft Portable Executable and Common Object File Format Specification\" href=\"http:\/\/www.microsoft.com\/whdc\/system\/platform\/firmware\/PECOFF.mspx\">Portable Executable specification<\/a>, the <em>SizeOfZeroFill<\/em> member of the <em>IMAGE_TLS_DIRECTORY<\/em> structure is not used (or supported) by the linker or the loader.  This means that in practice, all TLS template data is initialized, and the size of the memory block allocated for per-module implicit TLS does <em>not<\/em> include the <em>SizeOfZeroFill<\/em> member as the PE documentation (or certain <a title=\"An In-Depth Look into the Win32 Portable Executable File Format, Part 2\" href=\"http:\/\/msdn.microsoft.com\/msdnmag\/issues\/02\/03\/PE2\/figures.asp#fig11\">other publications<\/a> that appear to be based on said documentation) would seem to state.  (It seems that the <a title=\"wine\/dlls\/ntdll\/loader.c\" href=\"http:\/\/source.winehq.org\/source\/dlls\/ntdll\/loader.c#L736\">WINE folks<\/a> happened to get it wrong as well, thanks to the implication in the PE specification that the field is actually used.)<\/p>\n<p>Some programs abuse TLS callbacks for anti-debugging purposes (gaining code execution before the normal process entrypoint routine is executed by creating a TLS callback for the main process image), although this is, in practice, quite obvious as almost all PE images do not use TLS callbacks at all.<\/p>\n<p>Up through Windows Server 2003, the above is really all the loader needs to do with respect to supporting <em>__declspec(thread)<\/em>.  While this approach would appear to work quite well, it turns out that there are, in fact, some problems with it (if you&#8217;ve been following along thus far, you can probably figure out what they are).  More on some of the limitations of the Windows Server 2003 approach to implicit TLS next week.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time, I described the mechanism by which the compiler and linker generate code to access a variable that has been instanced per-thread via the __declspec(thread) extended storage class. Although the compiler and linker have essentially &#8220;set the stage&#8221; with respect to implicit TLS at this point, the loader is the component that &#8220;fills in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[10,5],"tags":[17,18,13],"_links":{"self":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/186"}],"collection":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=186"}],"version-history":[{"count":1,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/186\/revisions"}],"predecessor-version":[{"id":536,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/186\/revisions\/536"}],"wp:attachment":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=186"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}