Microsoft Visual C++ Compiler v.100 (the one for Visual Studio 2010) compiles the main function of the following short program:
__declspec(thread) int i = 0; int main() { i++; }
To this:
int main(int argc, char **argv) { 00CC1890 push ebp 00CC1891 mov ebp,esp 00CC1893 sub esp,0C0h 00CC1899 push ebx 00CC189A push esi 00CC189B push edi 00CC189C lea edi,[ebp+FFFFFF40h] 00CC18A2 mov ecx,30h 00CC18A7 mov eax,0CCCCCCCCh 00CC18AC rep stos dword ptr es:[edi] i++; 00CC18AE mov eax,dword ptr ds:[00CC8194h] 00CC18B3 mov ecx,dword ptr fs:[0000002Ch] 00CC18BA mov edx,dword ptr [ecx+eax*4] 00CC18BD mov eax,dword ptr [edx+00000104h] 00CC18C3 add eax,1 00CC18C6 mov ecx,dword ptr ds:[00CC8194h] 00CC18CC mov edx,dword ptr fs:[0000002Ch] 00CC18D3 mov ecx,dword ptr [edx+ecx*4] 00CC18D6 mov dword ptr [ecx+00000104h],eax } 00CC18DC xor eax,eax 00CC18DE pop edi 00CC18DF pop esi 00CC18E0 pop ebx 00CC18E1 mov esp,ebp 00CC18E3 pop ebp 00CC18E4 ret
So what is going on here? The interesting part here is this:
ecx,dword ptr fs:[0000002Ch]
What is at fs:[0000002Ch]? The fs segment is offset to start at the start of the Thread Environment Block (TEB). Microsoft won’t tell you much except for “don’t touch”. Wikipedia has more information. Offset 2Ch is a pointer to the Thread Local Storage (TLS) slots. So it stores a TLS index at 00CC8194h, looks up the data at that TLS slot, which apparently is a pointer to an array of thread local values for that thread – where the variable i is placed at offset 104h.
So Microsoft tells us that the TEB is an internal structure subject to change from one Windows version to another, and toying around with it is a big no-no. And yet their compiler happily generates code that directly accesses this “internal implementation detail”.
Hipocrisy much?