[llvm-dev] __attribute__((apple_abi)): targeting Apple/ARM64 ABI from Linux (and others)
Adrien Guinet via llvm-dev
llvm-dev at lists.llvm.org
Fri Oct 9 06:02:03 PDT 2020
Hello Tim,
Thanks for the details you provided! Answers & comments below.
On 10/8/20 11:15 AM, Tim Northover wrote:
> On Thu, 8 Oct 2020 at 08:28, Adrien Guinet via llvm-dev
> <llvm-dev at lists.llvm.org> wrote:
>> * this supposes that the original targeted CC is Apple ARM64 AAPCS. In its current form,
>> there is no way to support for instance vector calls (see for instance
>> https://github.com/aguinet/llvm-project/commit/c4905ded3afb3182435df30e527955031cb0d098#diff-f124368bac3e5d7be20450aa83b166daR218)
>
> I'm afraid I don't understand this point.
ARM64 defines two calling conventions: aapcs and aapcs-vfp
(https://developer.arm.com/documentation/dui0491/i/Compiler-specific-Features/--attribute----pcs--calling-convention-----function-attribute).
Using __attribute__((apple_abi)) in its current form would only allow to
target aapcs from a foreign OS, not aapcs-vfp.
>> * the fact that we can't target Apple's vector calls ABI shows that having one
>> CC_AArch64Apple (as CC_Win64 exists) calling convention might not be the right
>> implementation of this "apple_abi" attribute. Has someone better suggestions?
>
> Needing two calling conventions seems really odd to me, unless it's
> for genuinely different ABI slices (arm64 vs arm64e or arm64_32 for
> example), and even there I'm not sure.
See above. The idea would be to also have, for instance,
CC_AArch64Apple_VFP (even if I'm really not found of this). It could
also end up as a non-supported case.
>> The fact that va_start/va_end works by using the Linux ABI from a function whose arguments
>> use the Apple ABI seems completely magical to me, so if someone knows why this work I
>> would also be interested!
>
> It's a series of coincidences conspiring together, I think. Linux's
> varargs ABI doesn't change from the normal one, so functions have to
> store all GPRs and vector registers that might contain arguments (as
> well as where stack args start), and va_list describes where they were
> stored:
>
> typedef struct {
> void *stack;
> void *gr_top;
> void *vr_top;
> int gr_offs;
> int vr_offs;
> } va_list;
>
> This is what you're getting with your "va_list" declaration. While the
> Darwin one is just a double pointer, but conceptually
>
> typedef struct {
> void *stack;
> } va_list;
>
> because all anonymous args go on the stack there on Darwin.
>
> That means when you call (Darwin's) va_start in your vprintf function
It's Linux's va_start no?
> it "correctly" initializes the first field of that struct, leaving the
> rest garbage. The gr_offs and vr_offs fields decide whether to use
> gr_top/vr_top or stack to actually get the argument, and in this case
> if gr_offs happens to be >= 0 it'll "correctly" use the stack to
> retrieve everything. I'm guessing that happens to be the case for
> simple programs (quite possibly the stack is still zero-initialized if
> this is a trivial test-case).
Okay got it. So the good way to lower this va_start would be to correctly set the rest of
the structure to zero if va_start is called from a function which has an Apple ABI (while
targetting Linux)? (actually answered below)
> You're also getting very lucky in that a Darwin varargs function
> changes how much of the stack each argument uses, bringing it in line
> with the normal AAPCS (otherwise the entire forwarding enterprise
> would be doomed and you'd have to implement significant chunks of
> vprintf to repack the arguments).
Indeed!
> So, at a high level what you'll *want* to do to correctly forward from
> Darwin to Linux is make sure that always happens: initialize gr_offs
> and vr_offs to 0 to begin with so only the stack is available (I'd
> also set the *_top fields to NULL for good measure).
Okay that seems to answer my question just above.
> Take the time to be grateful you're not trying to go the other way, too!
Yes :)
>> * For variadic functions (which are among the functions that have different ABIs), GCC and
>> Clang have __builtin_ms_va_list. My understanding is that we should have the Apple
>> equivalent, but I'm not sure to completely understand what's at stake here. Said
>> differently, is this builtin used to make sure we use the va_list type of the Apple ABI,
>> should the need arise to forward it to another function that uses the Apple ABI?
>
> That, together with __builtin_ms_va_arg and __builtin_ms_va_start, are
> for if you have a Linux-side function that wants to make use of a
> va_list or anonymous args coming from Darwin code in a relatively
> agnostic way. I think what you're doing (here at least) is so
> intimately tied to bridging the two ABIs that using it would just be a
> fig-leaf.
Okay, thanks for the confirmation.
Regards
More information about the llvm-dev
mailing list