Hi,
When using Wine to run Windows ARM64 executables on Linux, there's one major ABI incompatibility between the two; Windows treats the x18 register as the reserved platform register, while it is free to be clobbered anywhere in code on Linux.
The Wine code sets up this register before passing control over to the Windows executable code, but whenever the Windows code calls a function implemented in Wine, this register ends up clobbered.
The initial solution is to compile Wine itself with the -ffixed-x18 flag, to treat the x18 register as reserved within Wine, so that no compiler generated code touches it. This works fine as long as Wine makes no calls to other libraries from the outside Linux distribution - but e.g. as soon as any glibc function is called, it can end up clobbered again.
The full, proper solution would of course to be rebuilding one's Linux distribution from scratch with -ffixed-x18 on every single library. But this is of course pretty much impractical.
My current makeshift workaround for the matter is to reroute calls from native Windows code to Wine functions via a relay wrapper, which backs up and restores the register. This works in practice, but hasn't been accepted upstream, as it is not deemed a correct/complete solution. Also, if the emulated Windows API functions do callbacks, the register would need to be restored before the callbacks call windows code.
Another idea which was raised in https://bugs.winehq.org/show_bug.cgi?id=38780#c13, which disucsses this matter, was if it would be possible to make Clang/LLVM always back up and restore x18 on any call to any other function, to make sure that the register maintains the right value as long as running in Wine code. (One concern is that this could end up rather expensive though.)
I didn't really find any straighforward way of starting to implement this however. Does anyone here happen to have ideas about how one could either implement this, or solve it in another way?
// Martin