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