On 22.04.2025 17:21, Martin Storsjö wrote:
On Sat, 12 Apr 2025, Jacek Caban wrote:

A proper ARM64EC implementation would be tricky, as it would need to handle
a different calling convention and possibly use exit thunks for imported
functions. Instead, we can simply use the x86_64 version.
---

I think this sounds reasonable - I guess it'd be quite messy to implement this in native arm64ec.


To elaborate on this: unlike other functions, the vararg calling convention differs significantly from aarch64, so we’d need a completely separate implementation. The function pointers we receive as arguments point to x64 export thunks in imported DLLs. The correct way to call these would be using __os_arm64x_check_icall, which additionally requires an exit thunk.

While ignoring the exit thunk would mostly work (e.g., unless msvcrt.dll is x86 dropped into the application directory or if the imported function is patched at runtime), it’s technically incorrect.

The exit thunk in this case would be $iexit_thunk$cdecl$i8$varargs. It’s typically generated by the compiler and is already present in some mingwex object files. Blindly referencing it would pull an unrelated object file from the archive. Currently, this happens to be getopt.o, but that’s subject to change. Again, that would likely work in most cases, but it’s not technically correct and could lead to very non-obvious side effects.

The proper solution would be to ensure the exit thunk is present in the same file as the code that uses it, but in this case it's a .S file. To keep it that way, we’d need to copy the exit thunk code manually rather than having the compiler generate it, which I’d prefer to avoid. Another approach would be to move the implementation to a .c file and either add a dummy C call to sscanf or implement _Arm64XGenerateThunk in Clang and use that.

None of these options seem particularly appealing, especially for functionality that’s non-essential and likely won’t matter in practice.


If this gets called from native arm64ec, I guess the thunks on that side handle the necessary interop. Did you try it?


This is an internal function, called by a few other functions that are built as ARM64EC, like vsscanf, so it always goes through the exit thunk. And yes, I tested it. BTW, while my recent patches are enough to get a working UCRT setup, testing msvcrt-os still requires tweaking some F_ARM_ANY usage.


Implementation wise, this is a bit problematic though - as you probably already thought of. :-) This is a bit annoying, since it's only needed for msvcrt.dll. We generally shouldn't need to target that much in new arm64ec builds - but for existing x86_64 deployments, it's quite likely to need to interop with msvcrt.dll builds. And for orthogonality of testing, for testing (msvcrt,ucrt) x (all architectures), it makes sense to make sure the msvcrt config is fully functional even here.


Yeah, I was tempted to just declare msvcrt-os unsupported on ARM64EC ;-). In general, I aimed for feature parity with aarch64, which does support it, though a similar argument could be made there as well.

Originally, I was going to suggest marking just the few functions that depend on __argtos as unsupported on ARM64EC. But once I added support for building x86_64 object files for __guard_dispatch_icall_dummy, this became easy enough that I went ahead and reused the same mechanism here.


@@ -2337,6 +2345,9 @@ libarm64/gcrt2.o: libarm64/gcrt0.o
libarm64/%.o: crt/%.c
    $(AM_V_CC)$(COMPILE) $(CPPFLAGSARM64) -c $< -o $@

+libarm64/%.x86_64.o: %.S
+    $(AM_V_CC)$(MKDIR_P) $(@D) && $(COMPILE) $(CPPFLAGSARM64) -target x86_64-windows-gnu -c $< -o $@
+

This is a bit problematic - this hardcodes a clang specific way of requesting a different architecture from a preexisting compiler. (The other similar option, -m32 and -m64, is compatible across tools.) E.g. if GCC would gain support for arm64ec, how would we do this? Would we require the user to have both arm64ec-w64-mingw32-gcc and x86_64-w64-mingw32-gcc available during the same build?


Yeah, we'd probably need to require two compilers to be available. That's how Wine handles it, it looks for a separate compiler for each enabled architecture, and if ARM64EC is enabled, it also looks for an x86_64 compiler in addition to the ARM64EC one. Wine’s build system is a lot more flexible in general, so it was easier to set that up there, but with enough effort, mingw-w64 could do something similar.


That said, while I’d love to be proven wrong, I don’t expect GCC to support ARM64EC anytime soon. I think we’re fine ignoring that possibility and keeping things simple for now and revisiting it if/when it actually becomes relevant.


Secondly, while doing it this Clang specific way - what requirements does this place on the x86_64 target in the Clang binary? What if I'm building llvm-mingw with ARCHS=arm64ec, so when using "-target x86_64-w64-mingw32", it won't find any includes? As this is a .S and not a .c file, it makes things a bit easier, and this particular file doesn't seem to include any other files at all, so this particular case probably works.


Yes, that’s a limitation, but for the cases where I’ve needed it, it hasn’t been an issue. Those .S files don’t include any headers anyway.


(Another hypothetical case would be if Clang would be built with LLVM_TARGETS_TO_BUILD="AArch64" only - but we probably don't need to care about that case.)


Yes, that wouldn’t work.


So as long as the source file doesn't need anything in the toolchain to be initialized for the x86_64 target, I guess this would be tolerable. But it is a pretty big design constraint in how this is built.

As I'm not so intimately familiar with the details of the thunking layer here and how to convert between x86_64 and arm64ec, I'm not sure how hard it would be to implement this in native arm64ec code, so I guess I'll have to take your word for it, that this is the best compromise.


As I mentioned earlier, it's not impossible, but I believe it would introduce more complexity than it's worth.


Thanks,

Jacek



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to