IIUC atexit isn't exported by ucrtbase, but still exists (maybe as a builtin) and is resolved to a module-local symbol which can be used to register functions executed on module process detach. It is called implicitly by C++ compilers to register static destructors.
-- v4: include: Define __cpuid(ex) as intrinsics when _MSC_VER is defined. include: Don't import atexit when building with ucrtbase.
From: Rémi Bernon rbernon@codeweavers.com
--- include/msvcrt/stdlib.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/msvcrt/stdlib.h b/include/msvcrt/stdlib.h index f3df662528a..fe23567e851 100644 --- a/include/msvcrt/stdlib.h +++ b/include/msvcrt/stdlib.h @@ -203,7 +203,11 @@ _ACRTIMP DECLSPEC_NORETURN void __cdecl _Exit(int); _ACRTIMP DECLSPEC_NORETURN void __cdecl _exit(int); _ACRTIMP DECLSPEC_NORETURN void __cdecl abort(void); _ACRTIMP int __cdecl abs(int); +#ifndef _UCRT _ACRTIMP int __cdecl atexit(void (__cdecl *)(void)); +#else +extern int __cdecl atexit(void (__cdecl *)(void)); +#endif _ACRTIMP double __cdecl atof(const char*); _ACRTIMP int __cdecl atoi(const char*); _ACRTIMP int __cdecl _atoi_l(const char*,_locale_t);
From: Rémi Bernon rbernon@codeweavers.com
--- include/msvcrt/intrin.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/msvcrt/intrin.h b/include/msvcrt/intrin.h index 7981e2798ba..5f9f6832353 100644 --- a/include/msvcrt/intrin.h +++ b/include/msvcrt/intrin.h @@ -15,15 +15,32 @@ extern "C" { #endif
+#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + #if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) + +#if defined(_MSC_VER) && (!defined(__has_builtin) || __has_builtin(__cpuidex)) +void __cpuidex(int info[4], int ax, int cx); +#pragma intrinsic(__cpuidex) +#else static inline void __cpuidex(int info[4], int ax, int cx) { __asm__ ("cpuid" : "=a"(info[0]), "=b" (info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(ax), "c"(cx)); } +#endif /* _MSC_VER */ + +#if defined(_MSC_VER) && (!defined(__has_builtin) || __has_builtin(__cpuid)) +void __cpuid(int info[4], int ax); +#pragma intrinsic(__cpuid) +#else static inline void __cpuid(int info[4], int ax) { return __cpuidex(info, ax, 0); } +#endif /* _MSC_VER */ + #endif
#if defined(__aarch64__) || defined(__arm64ec__)
I've rewritten the rpcndr changes into https://gitlab.winehq.org/wine/wine/-/merge_requests/6502. Is there something else that needs to be done differently?
I guess `(!defined(__has_builtin) || __has_builtin(__cpuidex))` is a bit awkward after defining to 0 if it's not defined, but it's meant to detect MSVC vs clang. Then I don't know if that's necessary here, as I suspect actual MSVC would never get there?
Jacek Caban (@jacek) commented about include/msvcrt/intrin.h:
extern "C" { #endif
+#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif
#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
+#if defined(_MSC_VER) && (!defined(__has_builtin) || __has_builtin(__cpuidex))
Similar to !6502, it may be enabled on mingw with `-fms-extensions`. Something like `__has_builtin(__cpuidex) || (defined(_MSC_VER) && !defined(__clang__))` would be more accurate.
Jacek Caban (@jacek) commented about include/msvcrt/stdlib.h:
_ACRTIMP DECLSPEC_NORETURN void __cdecl _exit(int); _ACRTIMP DECLSPEC_NORETURN void __cdecl abort(void); _ACRTIMP int __cdecl abs(int); +#ifndef _UCRT _ACRTIMP int __cdecl atexit(void (__cdecl *)(void)); +#else +extern int __cdecl atexit(void (__cdecl *)(void)); +#endif
I guess we could just drop `_ACRTIMP`. Ideally, we'd provide it in a static library on other CRTs too. Meantime, missing `_ACRTIMP` does not prevent linking to importlib, it just makes it slightly less efficient.
On Mon Sep 16 10:47:22 2024 +0000, Jacek Caban wrote:
I guess we could just drop `_ACRTIMP`. Ideally, we'd provide it in a static library on other CRTs too. Meantime, missing `_ACRTIMP` does not prevent linking to importlib, it just makes it slightly less efficient.
Thinking some more about it, maybe it's fine to not support it on older CRTs. It would make `atexit` support easier and we don't need to care that much about them...
On Mon Sep 16 11:26:19 2024 +0000, Jacek Caban wrote:
Thinking some more about it, maybe it's fine to not support it on older CRTs. It would make `atexit` support easier and we don't need to care that much about them...
I'm not sure to understand what you mean and how this actually should be done. As far as I understand `atexit` is exported by msvcrt, so I expect it to be an actual import that doesn't do the same as the ucrtbase-era `atexit` (ie: only works process-wide, not per-module) which is a symbol that would be provided by winecrt0?
On Mon Sep 16 12:39:39 2024 +0000, Rémi Bernon wrote:
I'm not sure to understand what you mean and how this actually should be done. As far as I understand `atexit` is exported by msvcrt, so I expect it to be an actual import that doesn't do the same as the ucrtbase-era `atexit` (ie: only works process-wide, not per-module) which is a symbol that would be provided by winecrt0?
I don't have such MSVC version at hand to check the linking, but the fact that it's exported doesn't mean that an application built with MSVC would import it directly. There are all sorts of tricks that the toolchain can do and I can see it declared without dllimport attribute in pre-UCRT headers too. mingw-w64, for example, provides DLL-aware version of `atexit` even when using msvcrt.dll (or crtdll.dll for that matter).