I forward it here for comments. Basing on the behavior of both GCC and Clang, `__cxa_thread_atexit` is used to register the destructor of thread_local objects directly, suggesting the first parameter should have `__thiscall` convention. libstdc++ used the default `__cdecl` convention and caused crashes on 1686-w64-mingw32 (see PR83562). But to my surprise, libcxxabi uses `__cdecl` too [1], but I haven't heard any of relevant reports so far. Original patch is attached in case you can't find it in gcc-patches. [1] https://github.com/llvm/llvm-project/blob/97b351a827677ebbedc10bfbce8ef8844c246553/libcxxabi/src/cxa_thread_atexit.cpp#L22 -------- 转发的消息 -------- 主题: Re: libstdc++: Attempt to resolve PR83562 日期: Tue, 27 Oct 2020 22:38:29 +0800 发件人: Liu Hao 收件人: Jason Merrill , GCC Patches 在 2020/10/8 22:56, Jason Merrill 写道: > > Hmm, why isn't the mingw implementation used for all programs?  That would avoid the bug. > There was a little further discussion about this [1]. TL;DR: The mingw-w64 function is linked statically and subject to issues about order of destruction. Recently mingw-w64 has got its own `__cxa_thread_atexit()` so libstdc++ no longer exposes it. This patch for libstdc++ fixes calling conventions for destructors on i686 so they match mingw-w64 ones. [1] https://github.com/msys2/MINGW-packages/issues/7096 [2] Below is a direct quote from #mingw-w64 on OFTC: (lh_ideapad is me and wbs is Martin Storsjö.) ``` [14:29:32] wbs, what was the rationale for the `__thiscall` convention for `__cxa_thread_atexit()` and `__cxa_atexit()` in our CRT? I suspect it is correct, but it is not specified anywhere in Itanium ABI. [14:30:41] In case of evidence for that, the GCC prototype (with default __cdecl) should be wrong. [14:31:10] See this: https://github.com/msys2/MINGW-packages/issues/7096 [14:52:05] lh_ideapad: itanium ABI doesn't really talk about windows things, but, the function that is passed to __cxa_thread_atexit is the object's destructor function, and when calling the destructor, which is technically a member function, it's done with the thiscall calling convention [14:52:31] lh_ideapad: example: https://godbolt.org/z/qbfWT1 (only clang as there's no gcc-mingw there, but if you try the same there you'll see the same thing) [14:52:35] Title: Compiler Explorer (at godbolt.org) [14:52:58] lh_ideapad: the destruct function shows that when calling __ZN7MyClassD1Ev, the destructor, it passes the object pointer in ecx, i.e. thiscall [14:53:42] lh_ideapad: and when adding the object to the cleanup list, the __ZN7MyClassD1Ev function is passed directly to ___cxa_thread_atexit, which then will need to call the function using the thiscall convention [14:59:54] lh_ideapad: so yes, I would agree with your patch changing libsupc++ to use thiscall [15:13:01] gcc is doing the same thing with a wrong calling convention , leaving a garbage value on i686-w64-mingw32. [15:13:38] yup, so definite +1 on your libsupc++ patch for that [15:14:00] then how about `__cxa_atexit`? [15:14:26] I would say it should work the same, but gcc doesn't normally use that one, right? [15:14:29] it's not used by GCC (the standard `atexit()` is used). [15:15:26] clang has a flag -fuse-cxa-atexit, which makes it use cxa_atexit instead of atexit [15:15:40] I was a bit dubious on it. [15:18:59] GCC has `-fuse-cxa-atexit` too . Let me check. [15:18:59] (I tested it), clang does use __cxa_atexit if the -fuse-cxa-atexit flag is used, and then the dtor (thiscall) is passed directly to __cxa_atexit, so that's +1 datapoint to that it should have thiscall. gcc doesn't use __cxa_atexit for i686 windows despite -fuse-cxa-atexit, so that's no points in either direction [15:19:28] both clang and gcc use a wrapper function that fixes the calling convention, when using atexit at least [15:20:22] `-fuse-cxa-atexit` seems to have no effect on `i686-w64-mingw32-g++`. [15:20:46] exactly. so in practice it doesn't matter for gcc, but I think libsupc++ should handle it the same [15:23:11] ok I will compose a new patch for both functions later today. [15:23:13] :) [15:23:25] \o/ [15:24:40] then for the other issue that the user was posting about; I remember testing and noticing that the mingw-w64-crt implementation of __cxa_thread_atexit doesn't work with emutls, but in all of my tests, it has been a non-issue as it has ended up using the libsupc++ code instead [15:50:50] probably static linking is broken, so one must link against shared libstdc++. [15:52:20] it doesn't matter whether it is the CRT or libsupc++ implementation that is linked statically. [15:53:13] it seems like current msys builds of libstdc++ doesn't include __cxa_thread_atexit in libstdc++ at all. I'm pretty sure I tested this back when I made the mingw version, but I'll investigate and try to pinpoint what changed (did gcc at some point start noticing that mingw-w64-crt contains it and stop providing their own?) or whether I just missed something when I tested it back when I wrote it... [15:59:47] I'll follow up on that other issue and mingw bugtracker issue, but I'll do a couple hours of comple testing/studying things first to be able to give an informed comment [16:15:34] * pamaury (~pamaury@ip-41.net-89-3-53.rev.numericable.fr) has joined [16:27:34] wbs, there is a check in `libstdc++-v3/configure.ac` around line 275. [16:29:22] lh_ideapad: yeah, but in my tests it doesn't pick up on it. I test by cross-bootstrapping a toolchain, so maybe this check runs before the mingw-w64-crt actually is built [16:29:50] so it doesn't detect if just bootstrapping once, but if building a new gcc in an already complete environment, it behaves differently [16:33:21] * Pali (~pali@0001caa5.user.oftc.net) has joined [16:34:52] ah, here it is: [16:34:52] # Only do link tests if native. Else, hardcode. [16:34:52] if $GLIBCXX_IS_NATIVE; then ``` -- Best regards, LH_Mouse