-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
I tried this code with rustc how-to-violate-an-abi.rs --target=aarch64-unknown-linux-gnu
:
#[repr(C, packed)]
pub struct PackedC {
a: u8,
b: u16,
}
#[no_mangle]
pub extern "C" fn exposed_illegal_struct(c: PackedC) -> PackedC {
PackedC { a: c.a +1, b: c.b -1 }
}
I expected to see this happen: At least a warning about violating the Procedure Call Standard for the Arm 64-bit Architecture ("AAPCS64").
Instead, this happened: the code passed without rustc erroring (until rustc errored on finding I haven't installed the right linker yet). Concerning. Perhaps I am doing something wrong?
Meta
rustc --version --verbose
:
rustc 1.57.0-nightly (51e514c0f 2021-09-12)
binary: rustc
commit-hash: 51e514c0fb4f9afcaae3b02dd9ccb93e15b30ef8
commit-date: 2021-09-12
host: x86_64-pc-windows-msvc
release: 1.57.0-nightly
LLVM version: 13.0.0
Details
This came up during discussion of the Arm ABI and bitfields. In essence, as it was explained to me: #[repr(C)]
and #[repr(packed)]
are not really quite compatible since compilers have a lot of liberty to intepret things like __attribute__((__packed__))
, which is, in any case, a compiler extension and not part of the C standard. As such, Arm actually explicitly disallows them in code that exposes an interface. Here we have some code which could do exactly that: return a type with an ABI-breaking combination of reprs.
To quote Arm (emphasis mine):
The AAPCS64 does not allow exported interfaces to contain packed structures or bit-fields. However a scheme for laying out packed bit-fields can be achieved by reducing the alignment, A, in the above rules to below that of the natural container type. ARMCC uses an alignment of A=8 in these cases, but GCC uses an alignment of A=1.
The varying alignment described here is itself an excellent example as to how #[repr(packed)]
can be subject to differing interpretations between compilers, and would ideally have a limited amount of exposure to the logic outside a single compiler on any system. Of course, we don't have packed bitfields in Rust yet, but we do have packed structs!
This may fall under the improper_ctypes
lint, however as it is apparently an explicit ABI violation on this architecture, something a bit more stern than just a warning does seem like it may be appropriate if we detect it "leaking out". It also does seem doubtful we can truly be inter-compiler consistent in cases where the ABI is any less specified than such a quite thorough algorithm. Of course, even on Arm, something like this may be required of a Rust programmer for interacting with legacy code that decides it is "too good" for the AAPCS anyways, though we might need additional hints for producing a proper layout (and ideally a better solution can be found).