Hi Ard and Leif,
We encountered an issue with passing a VA_LIST across an
ABI boundary on AARCH64 that I wanted to discuss with
you. And the answer may well be: don't pass a VA_LIST
across an ABI boundary :).
The situation we encountered was in the
BaseCryptoLibOnProtocolPpi where a VA_LIST is
directly passed across a protocol:
https://github.com/tianocore/edk2/blob/b03a21a63e3bd001f52c527e5a57feddb53a690b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c#L2485-L2490.
On
AARCH64, this fails if the caller is built with GCC
and the protocol producer is built with CLANGPDB (or
vice-versa).
On X64, this works fine because VA_LIST is coerced on all
toolchains to have the MS ABI (__builtin_ms_va_list vs
__builtin_va_list):
https://github.com/tianocore/edk2/blob/b03a21a63e3bd001f52c527e5a57feddb53a690b/MdePkg/Include/Base.h#L594-L606.
On AARCH64, we have GCC (and CLANGDWARF) using __builtin_va_list
and CLANGPDB falls into the MSVC ARM64 case because _M_ARM64 is
defined:
https://github.com/tianocore/edk2/blob/b03a21a63e3bd001f52c527e5a57feddb53a690b/MdePkg/Include/Base.h#L580-L585.
Using char * with __builtin_va_list is incompatible. Even if CLANGPDB
is fixed to not hit the MSVC case and to use __builtin_va_list instead,
it uses the MS ABI, not the GCC ABI. Those are incompatible, illustrated
here (note this uses the MinGw clang, i.e. the windows-gnu target,
because godbolt doesn't seem to do well with windows-msvc, but the
problem is the same):
https://godbolt.org/z/8Wchjsva3.
As noted above, x64 GCC supports using __builtin_ms_va_list and so
X64 works here. But ARM64 GCC doesn't support this. I have not found
a way to coerce CLANGPDB to use the GCC ABI (which clearly clang
supports, but seems to only be chosen based on target, perhaps I have
just missed it).
I _think_, but would love to get feedback on, that really we should
not be relying on compiler built in types here and only use char * for
the VA_LIST and our own handling it; caveat: I don't know what the perf
implications would be.
However, to change this would also risk breaking existing separately
compiled binaries that pass VA_LIST as an argument (I imagine this
is a pretty small set, however, if it exists at all). I.e. all existing
GCC AARCH64 binaries would be using the GCC ABI which would break
here.
As I started this thread off with, another option is to say VA_LIST
should never be passed as an arg across ABIs on AARCH64. Which in
general does seem risky at best. However, this may be hard to enforce
and may leave open other potential issues.
I will note that variadic functions themselves are fine across ABI
boundaries, e.g. InstallMultipleProtocolInterfaces, because they
use the standard calling convention to pass the arguments, its just
for the compiler built in types that are a problem.
What are your thoughts here? Please feel free to point out if I've
misinterpreted any of this :)
Oliver
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#121935): https://edk2.groups.io/g/devel/message/121935
Mute This Topic: https://groups.io/mt/119278849/21656
Group Owner: [email protected]
Unsubscribe: https://edk2.groups.io/g/devel/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-