-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Static initializers (C++) are not called with Microsoft Visual Studio Linker #9585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
If anyone could provide some information on where the code generation for all of this happens, I'd be quite happy to look into adding support for msvc... |
Static ctors are normally run from the hidden routine which is executed before main(). So, you need to figure out how vcpp handles this, what does it call, etc. |
Yes, I'm already aware of how msvc handles static initializers - I was more interested about where in llvm/clang the static initializer information is put into the object file. |
I have a working fix for this, although it isn't widely tested yet. To properly get the MS CRT to call static constructors, they need to be put into a specially named section that gets picked up by the MSVC linker. In TargetLoweringObjectFileCOFF::Initialize(...) when LLVM sets up StaticCtorSection, one could do something like: Triple T(((LLVMTargetMachine&)TM).getTargetTriple()); .. getContext().getCOFFSection(useMSVCLinkerCompatibleGlobalCtorDtor ? ".CRT$XCU" : ".ctors", The .CRT$XC* section/group is read by the MSVC linker and function pointers are placed into an array (ordered by the last letter in the group name) that is called during __tmainCRTStartup. (http://msdn.microsoft.com/en-us/library/bb918180.aspx) I've tested this with a previously-broken project and it fixes it perfectly, along with producing the right looking stuff in DUMPBIN. The other trick is to also get static destructors working. The static constructor wrappers (__cxx_global_var_init et al) for objects that have dtors contain a call to __cxa_atexit(the_dtor_fn) which needs to be implemented on MSVC targets. Forward the call directly to atexit, thus: extern "C" void and the CRT will similarly unwind the construction order on exit. All that in place, things seem to work, at least in the test case(s) I've got here. Further testing required. I don't claim the above is the correct/perfect answer, but perhaps it will help focus in on a final solution. |
A transparent fix for dtors is to just use the "atexit" symbol instead of "__cxa_atexit" during CodeGenFunction::EmitCXXGlobalDtorRegistration(...) when targeting the MSVC linker. This then resolves to the MSVC equivalent directly, no code changes required on the user end. I tried patching the tail end of the above function as below (obviously these kind of specifications all need to live somewhere in the Targets configuration stuff) llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
|
I just got through manually working around this bug in my compiler. The workarounds described by Harry Denholm worked, with the caveat that the symbols generated into the .CRT$XCU section must also be protected against internalization. libcmt.lib's mainCRTStartup appears to be unable to run initializers with internal linkage. |
This should be fixed by r151289. |
Extended Description
Static initializers in C++, defined by @llvm.global_ctors are not called when object files are linked by MSVC linker. I've attached a simple test file. Other tool chains (MinGW gcc) are okay in Windows.
The attached file should print out:
"foo_initializer"
"11"
I'm unclear which component is culprit for this bug. Please move this bug reporting if better component section fits.
[1] MSVC C++ - Okay
[2] MinGW-gcc - Okay
[3] MinGW-llvm-gcc - Okay
[4] Clang - NOT okay (Clang will call MSVC's "link.exe")
===> However, linking with gcc's is okay.
The text was updated successfully, but these errors were encountered: