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