When we remove the CRT we broke the static initializer in the code.
Now the static variables are not initialized anymore.
Also setting the _tls_index to 0 is wrong and will result in static variables inside function to not be initialized.
When there is a static variable inside a function the _tls_index get look to see if that variable is initialized or not.
Indeed _tls_index work with _Init_thread_header to ensure that the given static var would be initialized one.
I figured out this because in my code base I have the fix for the static variable initialization (using __xc_a and initerm) but when I was implementing the debug system, the first approach was to use static variables and the DEBUGInitializeValue function was never called.
Upon inspecting the CRT source code I'm now able to make that statics works as well.
Here are the gist of my msvc CRT replacament if any one is interested.

If all you want is to avoid thread-safe static initializations (which were introduced in VS2015), you can simply use /Zc:threadSafeInit- compiler argument. This will give you pre-C++11 static initialization behaviour - without dependency on C++ runtime.

But at this point I feel like it would be easier just to avoid C++ static variables than to do this kind of stuff. Which can change from one VS version to another. Not even talking about different platform or different compilers.

Similarly - that's why you also avoid __declspec(thread) for TLS and just directly call TlsGetValue/TlsSetValue when needed.