[llvm-dev] Automatically backing up and restoring x18 around function calls on AArch64?

James Y Knight via llvm-dev llvm-dev at lists.llvm.org
Tue Apr 30 06:18:14 PDT 2019


On Fri, Apr 26, 2019 at 8:30 AM Martin Storsjö via llvm-dev <
llvm-dev at lists.llvm.org> wrote:

> 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.



You don't actually need to back up the value, since it doesn't change, just
copy it from another per-thread location back into x18, right?

Anyhow, this "workaround" seems like the correct solution, IMO. You have
two slightly-incompatible ABIs, and using an adapter between the two seems
entirely reasonable. As long as this adapter code is either written in asm,
or compiled with -ffixed-x18, you can be sure that the x18 won't be
overwritten by the compiler inside the adapter function. Yes, it does need
to be invoked both on the return path back to windows code, and on callouts
to windows functions, but that doesn't seem like it should be terribly
tricky to arrange?

Having the compiler handle it for you might seem nice, but since this is a
value which is not part of the Linux ABI at all, copying it yourself as
needed really seems like the best plan. Otherwise, you'd have to teach the
compiler where the secondary thread-local location it's stashed is, and how
to retrieve it from there. Which doesn't seem like the compiler ought to be
in the business of doing.


On Fri, Apr 26, 2019 at 8:30 AM Martin Storsjö via llvm-dev <
llvm-dev at lists.llvm.org> wrote:

> 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
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190430/0a3992b4/attachment.html>


More information about the llvm-dev mailing list