Bug 33823 - bitfields on packed struct aligns by a few bits if the types differ
Summary: bitfields on packed struct aligns by a few bits if the types differ
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.2.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: ABI, documentation
Depends on:
Blocks:
 
Reported: 2007-10-20 01:47 UTC by Alexandre Pereira Nunes
Modified: 2021-09-17 06:59 UTC (History)
1 user (show)

See Also:
Host: i486-linux-gnu
Target: i486-linux-gnu
Build: i486-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2008-02-14 23:04:27


Attachments
A complete testcase. (365 bytes, text/x-csrc)
2007-10-20 01:49 UTC, Alexandre Pereira Nunes
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alexandre Pereira Nunes 2007-10-20 01:47:39 UTC
I have two structs (the unions are there for the sake of testing, it still behaves the same without them):

#define ATTRIBUTE_PACKED_STRUCT __attribute__((gcc_struct,packed))
#include <stdio.h>
#include <stdint.h>

typedef union  ATTRIBUTE_PACKED_STRUCT
{
  struct ATTRIBUTE_PACKED_STRUCT {
    uint8_t a:1,
            b:7,
            c:7;
    uint16_t d:16;
    uint8_t e:7;
    uint8_t f:7;
    uint16_t g:10;
    uint16_t h:10;
    uint16_t i:12;
    uint8_t  j:7;
    uint8_t k:8;
    uint16_t l:15;
  };
  unsigned char values[14];
} test_struct;

typedef union  ATTRIBUTE_PACKED_STRUCT
{
  struct ATTRIBUTE_PACKED_STRUCT {
    uint32_t a:1,
            b:7,
            c:7;
    uint32_t d:16;
    uint32_t e:7;
    uint32_t f:7;
    uint32_t g:10;
    uint32_t h:10;
    uint32_t i:12;
    uint32_t  j:7;
    uint32_t k:8;
    uint32_t l:15;
  };
  unsigned char values[14];
} test_struct2;

These structs have the same effective size, i.e., removing them from the unions, and having sizeof() applied to them yelds the 14 bytes size, but the members dispostion differs, i.e. the 'e' member is a bit ahead in the first struct (test_struct) than in the second. 

I didn't expect the type change to force an alignment. It that's standard behaviour, then I would like to propose a documentation request; The ms_struct alignment is described quite well on gcc's page, but gcc's default one isn't.

If that's not expected behaviour, then what would be? In case it is, could someone please point me to a documentation source, i.e. an ISO C pointer or whatever reasoning is behind this, if any?

Thanks.
Comment 1 Alexandre Pereira Nunes 2007-10-20 01:49:07 UTC
Created attachment 14374 [details]
A complete testcase.

I compiled with gcc -ggdb3 file.c -o file, no optimization flags.
Comment 2 Richard Biener 2007-10-20 09:47:33 UTC
The standard puts all the burden on the implementation (See 6.7.2.1/10).
The GCC manual in turn says the behavior is specified by the ABI (4.9 Structures, unions, enumerations, and bit-fields), which would be the sysv ABI which I
don't have handy right now.
Comment 3 Alexandre Pereira Nunes 2007-10-20 12:20:15 UTC
(In reply to comment #2)
> The standard puts all the burden on the implementation (See 6.7.2.1/10).
> The GCC manual in turn says the behavior is specified by the ABI (4.9
> Structures, unions, enumerations, and bit-fields), which would be the sysv ABI
> which I
> don't have handy right now.
> 

Does the ABI dictates the case of how gcc should *pack* the structures? I've seem that gcc packs structures in a very similar (if not identical) fashion on some targets (ix86-linux-gnu, arm-elf, mingw without -mms-bitfields, at least), are they covered by sysv ABI too? Is it a default on gcc whenever the target has no particular semantics (as arm-elf, which I suppose does not derive from the ARM published ABIs at all)?


Comment 4 Alexandre Pereira Nunes 2007-10-20 12:55:11 UTC
(In reply to comment #2)
> The standard puts all the burden on the implementation (See 6.7.2.1/10).
> The GCC manual in turn says the behavior is specified by the ABI (4.9
> Structures, unions, enumerations, and bit-fields), which would be the sysv ABI
> which I
> don't have handy right now.
> 

http://www.sco.com/developers/devspecs/abi386-4.pdf

Would that be it?
Comment 5 Alexandre Pereira Nunes 2007-10-20 13:35:24 UTC
(In reply to comment #4)
> (In reply to comment #2)
> > The standard puts all the burden on the implementation (See 6.7.2.1/10).
> > The GCC manual in turn says the behavior is specified by the ABI (4.9
> > Structures, unions, enumerations, and bit-fields), which would be the sysv ABI
> > which I
> > don't have handy right now.
> > 
> 
> http://www.sco.com/developers/devspecs/abi386-4.pdf
> 
> Would that be it?
> 

I couldn't find (ok, I didn't try hard enough) the generic abi, but the 386 abi only tells about the case of bitfields on regular structures, i.e. those without the packed attribute. I do believe that ABI-conformant structures are always padded (aligned), and the packed structures are outside of the ABI scope... I'll try and see if I find the generic sysv abi docs.
Comment 6 Alexandre Pereira Nunes 2007-11-02 16:58:13 UTC
From the gcc internals (http://gcc.gnu.org/onlinedocs/gccint/Storage-Layout.html):

— Target Hook: bool TARGET_MS_BITFIELD_LAYOUT_P (tree record_type)

    This target hook returns true if bit-fields in the given record_type are to be laid out following the rules of Microsoft Visual C/C++, namely: (i) a bit-field won't share the same storage unit with the previous bit-field if their underlying types have different sizes, and the bit-field will be aligned to the highest alignment of the underlying types of itself and of the previous bit-field; (ii) a zero-sized bit-field will affect the alignment of the whole enclosing structure, even if it is unnamed; except that (iii) a zero-sized bit-field will be disregarded unless it follows another bit-field of nonzero size. If this hook returns true, other macros that control bit-field layout are ignored.

    When a bit-field is inserted into a packed record, the whole size of the underlying type is used by one or more same-size adjacent bit-fields (that is, if its long:3, 32 bits is used in the record, and any additional adjacent long bit-fields are packed into the same chunk of 32 bits. However, if the size changes, a new field of that size is allocated). In an unpacked record, this is the same as using alignment, but not equivalent when packing.

    If both MS bit-fields and `__attribute__((packed))' are used, the latter will take precedence. If `__attribute__((packed))' is used on a single field when MS bit-fields are in use, it will take precedence for that field, but the alignment of the rest of the structure may affect its placement. 

... it seems like that the packed attribute has the power of nulify the ms_struct attribute, but not the gcc_struct one, regarding a rather non-uniform behaviour if the underlying ABIs are different. It also means that I could use ms_struct,packed in a portable way (even on architetures where the ms_struct isn't even an alternative), but gcc_struct,packed is less portable. Right?
Comment 7 Richard Biener 2008-02-14 21:33:54 UTC
Yes, so for packed structs (which are a GCCism), GCC sets the rule.  Better
documentation is certainly appreciated, but - what is the bug here?  Did
the behavior change (I think it did for some 3.x releases) recently?
Comment 8 Alexandre Pereira Nunes 2008-02-14 22:06:47 UTC
(In reply to comment #7)
> Yes, so for packed structs (which are a GCCism), GCC sets the rule.  Better
> documentation is certainly appreciated, but - what is the bug here?  Did
> the behavior change (I think it did for some 3.x releases) recently?
> 

I'm not sure if it's a bug, call it a clarification request, that may or may not involve a bug: It's stated somewhere in gcc docs that gcc tries to do things uniformly, only diverging between targets where there's a compelling reason to do so. So what I'm asking is:

- Is the attribute((packed)) behaviour consistent between gcc ports regarding bitfield alignments? If not, why?

- If attribute((packed)) is not consistent between gcc ports, could it be made so? At least sysv abi (as far as I've read) does not mandate anything about the bitfields within a word. I've not pointed to any ABI that does, however, that was the explanation I've got. That's where I said the abi could change (for several arches). You may say it's not worthy, and I would agree, but here is where the "bug" would (or would not) lie.

- If not and there's no point changing it, could there be another attribute, or anything, that would have that effect (uniformity between ABIs)?

I understand perfectly that using structures like that is meant to be non-portable, but it's quite handy to have something like that without too much worry about platforms, since altough I develop for several arches, almost all of them today have a gcc port, and I know there are others with similar issues.

If this revert to be a non-bug and I can still hold a feature request on it, I would be satisfied.
Comment 9 Richard Biener 2008-02-14 23:04:27 UTC
We can't change the current behavior/ABI obviously.  But the request for better
documentation is correct.
Comment 10 Alexandre Pereira Nunes 2008-02-14 23:15:51 UTC
(In reply to comment #9)
> We can't change the current behavior/ABI obviously.  But the request for better
> documentation is correct.
> 

Would it be feasibly to have a non-fatal testcase for this, so that it would be easy to catch (and document) which (if any) targets deviates from this pattern?