@@ -89,7 +89,92 @@ __declspec(allocate(".CRT$XIY")) static _PF _ctor = &ctor;
89
89
__declspec(allocate (".CRT$XTY" )) static _PF _dtor = & dtor ;
90
90
91
91
#pragma data_seg(pop)
92
- #endif
92
+
93
+ /*********************************************************
94
+ * Windows before Windows 8.1 does not support TLS alignment to anything
95
+ * higher than 8/16 bytes for Win32 and Win64, respectively.
96
+ * Some optimizations in LLVM (e.g. using aligned XMM access) do require
97
+ * higher alignments, though. In addition, the programmer can use align()
98
+ * to specify even larger requirements.
99
+ * Fixing the alignment is done by adding a TLS callback that allocates
100
+ * a new copy of the TLS segment if the current one is not aligned properly.
101
+ */
102
+
103
+ __declspec(thread ) void * originalTLS ; // saves the address of the original TLS to restore it before termination
104
+
105
+ extern void * * GetTlsEntryAdr ();
106
+ int _tls_index ;
107
+
108
+ BOOL WINAPI fix_tlsAlignment (HINSTANCE hModule , DWORD fdwReason , LPVOID lpvReserved )
109
+ {
110
+ if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH )
111
+ {
112
+ if (originalTLS )
113
+ {
114
+ // restore original pointer
115
+ void * * tlsAdr = GetTlsEntryAdr ();
116
+ void * allocAdr = ((void * * )* tlsAdr )[-1 ];
117
+ * tlsAdr = originalTLS ;
118
+ HeapFree (GetProcessHeap (), 0 , allocAdr );
119
+ }
120
+ }
121
+ else
122
+ {
123
+ // crawl through the image to find the TLS alignment
124
+ char * imageBase = (char * )hModule ;
125
+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER )hModule ;
126
+ PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS )(imageBase + pDosHeader -> e_lfanew );
127
+ PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER )(pNtHeaders + 1 );
128
+ PIMAGE_DATA_DIRECTORY dataDir = pNtHeaders -> OptionalHeader .DataDirectory + IMAGE_DIRECTORY_ENTRY_TLS ;
129
+ if (dataDir -> VirtualAddress ) // any TLS entry
130
+ {
131
+ PIMAGE_TLS_DIRECTORY tlsDir = (PIMAGE_TLS_DIRECTORY )(imageBase + dataDir -> VirtualAddress );
132
+ int alignShift = ((tlsDir -> Characteristics >> 20 ) & 0xf );
133
+
134
+ if (alignShift )
135
+ {
136
+ int alignment = 1 << (alignShift - 1 );
137
+ void * * tlsAdr = GetTlsEntryAdr ();
138
+ if ((SIZE_T )* tlsAdr & (alignment - 1 ))
139
+ {
140
+ // this implementation does about the same as Windows 8.1.
141
+ HANDLE heap = GetProcessHeap ();
142
+ SIZE_T tlsSize = tlsDir -> EndAddressOfRawData - tlsDir -> StartAddressOfRawData + tlsDir -> SizeOfZeroFill ;
143
+ SIZE_T allocSize = tlsSize + alignment + sizeof (void * );
144
+ void * p = HeapAlloc (heap , 0 , allocSize );
145
+ if (!p )
146
+ return 0 ;
147
+
148
+ void * aligned = (void * )(((SIZE_T )p + alignment + sizeof (PVOID )) & ~(alignment - 1 ));
149
+ void * old = * tlsAdr ;
150
+ ((void * * )aligned )[-1 ] = p ; // save base pointer for freeing
151
+ memcpy (aligned , old , tlsSize );
152
+ * tlsAdr = aligned ;
153
+ originalTLS = old ;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ return 1 ;
159
+ }
160
+
161
+ // the C++ TLS callbacks are written to ".CRT$XLC", but actually start after ".CRT$XLA".
162
+ // Using ".CRT$XLB" allows this to come first in the array of TLS callbacks. This
163
+ // guarantees that pointers saved within C++ TLS callbacks are not pointing into
164
+ // abandoned memory
165
+
166
+ typedef BOOL WINAPI _TLSCB (HINSTANCE , DWORD , LPVOID );
167
+
168
+ #pragma data_seg(push)
169
+
170
+ #pragma section(".CRT$XLB", long, read)
171
+
172
+ #pragma data_seg(".CRT$XLB")
173
+ __declspec(allocate (".CRT$XLB" )) static _TLSCB * _pfix_tls = & fix_tlsAlignment ;
174
+
175
+ #pragma data_seg(pop)
93
176
94
177
#endif
95
178
179
+ #endif // _WIN32
180
+
0 commit comments