lkml.org 
[lkml]   [2021]   [Mar]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
SubjectRe: [kbuild-all] Re: include/linux/compiler_types.h:315:38: error: call to '__compiletime_assert_536' declared with attribute error: BUILD_BUG_ON failed: offsetof(struct can_frame, len) != offsetof(struct canfd_frame, len) || offsetof(struct can_frame, d
From
Date


On 23.03.21 21:54, Rasmus Villemoes wrote:
> On 23/03/2021 19.59, Oliver Hartkopp wrote:
>>
>>
>> On 23.03.21 15:00, Rasmus Villemoes wrote:
>
>>> Now what CONFIG_* knobs are responsible for putting -mabi=apcs-gnu in
>>> CFLAGS is left as an exercise for the reader. Regardless, it is not a
>>> bug in the compiler. The error is the assumption that this language
>>>
>>> "Aggregates and Unions
>>>
>>> Structures and unions assume the alignment of their most strictly
>>> aligned component.
>>
>> (parse error in sentence)
>
> It was a direct quote, but I can try to paraphrase with an example. If
> you have a struct foo { T1 m1; T2 m2; T3 m3; }, then alignof(struct foo)
> = max(alignof(T1), alignof(T2), alignof(T3)). Same for a "union foo".
>
> But this is specifically for x86-64; for (some flavors of) ARM, other
> rules apply - namely, alignof(T) is 4 unless T is char or short (or
> (un)signed variants), ignoring bitfields which have their own rules.
> Note that while
>
> union u {char a; char b;}
>
> has alignment 4 on ARM and 1 on x86-64, other types are less strictly
> aligned on ARM; e.g. s64 aka long long is 8-byte aligned on x86-64 but
> (still) just 4-byte aligned on ARM. And again, this is just for specific
> -mabi= options.
>
>>> Each member is assigned to the lowest available offset with the
>>> appropriate
>>> alignment. The size of any object is always a multiple of the object‘s
>>> alignment."
>>>
>>> from the x86-64 ABI applies on all other architectures/ABIs.
>>>
>>>> I'm not a compiler expert but this does not seem to be consistent.
>>>>
>>>> Especially as we only have byte sizes (inside and outside of the union)
>>>> and "A field with a char type is aligned to the next available byte."
>>>
>>> Yes, and that's exactly what you got before the anon union was
>>> introduced.
>>
>> Before(!) the union there is nothing to pad.
>
> Just to be clear, my "before" was in the temporal sense, i.e. "prior to
> commit ea7800565a128", all the u8s in struct can_frame were placed one
> after the other. But after that commit, struct can_frame has a new
> member replacing can_dlc which happens to occupy 4 bytes (for some
> ABIs), pushing the subsequent members __pad, __res0 and len8_dlc
> (formerly known as __res1) ahead.
>
>>>> The union is indeed aligned to the word boundary - but the following
>>>> byte is not aligned to the next available byte.
>>>
>>> Yes it is, because the union occupies 4 bytes. The first byte is shared
>>> by the two char members, the remaining three bytes are padding.
>>
>> But why is the union 4 bytes long here and adds a padding of three bytes
>> at the end?
>
> Essentially, because arrays. It's true for _any_ type T that sizeof(T)
> must be a multiple of alignof(T). Take an array "T x[9]". If x[0] is
> 4-byte aligned, then in order for x[1] to be 4-byte aligned as well,
> x[0] must occupy a multiple of 4 bytes.
>
> It doesn't matter at all that this happens to be an anonymous union.
> Layout-wise, you could as well have a definition
>
> union uuu { __u8 len; __u8 can_dlc; }
>
> and made struct can_frame
>
> struct can_frame {
> canid_t can_id;
> union uuu u;
> __u8 __pad;
> ...
> };
>
> (you lose the anonymity trick so you'd have to do frame->u.can_dlc
> instead of just frame->can_dlc). You have a member with alignof()==4 and
> sizeof()==4; that sizeof() cannot magically become 1 just because that
> particular instance of the type is not part of an array. Imagine what
> would happen if the compiler pulled subsequent char members into
> trailing padding of a previous compound member. E.g. consider
>
> struct a { int x; char y; } // alignof==4, sizeof==8, offsetof(y)==4
> struct b { struct a a; char z; }
>
> If I have a "struct b *b", I'm allowed to do "&b->a" and get a "pointer
> to struct a". Then I can do memset(&b->a, 0, sizeof(struct a)). Clearly,
> z must not have been placed inside the trailing padding of struct a.
>
> Rasmus
>

Thanks Rasmus!

@Marc: Looks like we can not get around the __packed() fix :-(

At least we now have some more documentation to be referenced and I
would suggest to point out that some compilers handle the union
alignment like this.

To make clear in the comments what we are suppressing here any why.

Many thanks,
Oliver

\
 
 \ /
  Last update: 2021-03-24 10:11    [W:0.087 / U:0.040 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site