Date: Mon, 1 Feb 2010 19:39:23 +0100 From: Luigi Rizzo <rizzo@iet.unipi.it> To: "M. Warner Losh" <imp@bsdimp.com> Cc: svn-src-head@FreeBSD.org, luigi@FreeBSD.org, src-committers@FreeBSD.org, svn-src-all@FreeBSD.org, brde@optusnet.com.au Subject: Re: svn commit: r203343 - head/sys/netinet Message-ID: <20100201183923.GA32901@onelab2.iet.unipi.it> In-Reply-To: <20100201.103803.850602504823287588.imp@bsdimp.com> References: <201002011413.o11EDiPm074656@svn.freebsd.org> <20100202012830.B1230@besplex.bde.org> <20100201.103803.850602504823287588.imp@bsdimp.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Feb 01, 2010 at 10:38:03AM -0700, M. Warner Losh wrote: > I concur with Bruce's assessment. Leave well enough alone. We don't > support those other compilers in the rest of the tree. These are userland-visible system headers so the change is not for building the system but for building generic userland programs on FreeBSD with other compilers. This said (sorry, i did not yet see Bruce's comment except in your email) if i understand Bruce's comment well, the problem is that no matter how we code it, bitfield layout is non specified, and we need non-portable __packed and __align and actual verification that things work as we want with a given compiler. > In particular, ARM generally gets broken when people naively monkey > with these sorts of thing. I'll be quite put-out if this is another > such change. Did you test it? No i did not test it on ARM. But i cannot think how a compiler would pack a u_int bitfield to 1 byte and refuse to do the same with an u_char (or uint8_t if you like it better). At a quick test, bitfields declared using u_char or *int8_t grep -Er 'int8_t|u_char' ~/FreeBSD/head/sys | grep ':[1-9]' | grep -v .svn appear approximately 800 times in 60 files including a number of device drivers, sys/dev/ciss/cissreg.h, sys/dev/ciss/cissio.h, sys/dev/usb/usbdi.h and stuff that might be arm-related e.g. sys/dev/usb/controller/avr32dci.h sys/dev/usb/controller/atmegadci.h On these grounds (we already have 800 such instances, and my changes are meant to improve compatibility of our system) I'd like the changes to remain (possibly replacing u_char with uint8_t if that looks better). cheers luigi > Warner > > In message: <20100202012830.B1230@besplex.bde.org> > Bruce Evans <brde@optusnet.com.au> writes: > : On Mon, 1 Feb 2010, Luigi Rizzo wrote: > : > : > Log: > : > use u_char instead of u_int for short bitfields. > : > : This clobbers my ip.h rev.1.15 and tcp.h rev.1.9 (1998), which fixed > : the type of these struct members. In C, bit-fields have type _Bool, > : int, signed int or unsigned int. Other types are unporortable > : (common extensions; C99 J.5.8). > : > : > For our compiler the two constructs are completely equivalent, but > : > some compilers (including MSC and tcc) use the base type for > : > alignment, > : > which in the cases touched here result in aligning the bitfields > : > to 32 bit instead of the 8 bit that is meant here. > : > : Not quite true. gcc also uses the base type for alignment, but > : doesn't > : document the details AFAIK. The alignment requirements for the base > : type > : bogusly affects the alignment of the struct: the struct is padded at > : the > : end as if the base type is use for a non-bit-field struct member. > : Thus > : > : sizeof(struct { int8_t m:1; }) == 1; /* on normal 32-bit arches */ > : sizeof(struct { int16_t m:1; }) == 2; /* on normal 32-bit arches */ > : sizeof(struct { int_32_t m:1; }) == 4; /* on normal 32-bit arches */ > : sizeof(struct { int64_t m:1; }) == 8; /* on 64-bit arches */. > : > : However, gcc is not so broken as to give this excessive alignment for > : the bit-fields themselves. Thus > : > : sizeof(struct c { char c[3]; int_32_t m:1; }) == 4; > : > : The other compilers apparently extend the broken alignment to the > : bit-fields themselves. This is permitted by C99, but it is unwanted > : and is especially undesirable since C99 requires the _Bool/int/u_int > : type and doesn't provide any control over the alignment. > : > : C99 doesn't even require the alignment of bitfields to be documented > : AFAICS. It says that the alignment is "unspecified" (meaning surely > : that C99 doesn't specify it and not so surely that implementations > : document it, but implementations should document it). Anyway, the > : alignment is too MD to depend on, so bit-fields are simply unusable > : to lay out structs where the layout must be precise. (It is > : technically > : impossible to control the layout of a struct even without bit-fields, > : but only bit-fields are certain to cause problems.) > : > : > Note that almost all other headers where small bitfields > : > are used have u_int8_t instead of u_int. > : > : There is a lot of broken code out there, and now a lot in FreeBSD, > : though > : I fixed all instances of this bug in FreeBSD GENERIC during 1993-1998. > : > : > MFC after: 3 days > : > : Backout after: < 3 days. > : > : > Modified: > : > head/sys/netinet/ip.h > : > head/sys/netinet/tcp.h > : > > : > Modified: head/sys/netinet/ip.h > : > ============================================================================== > : > --- head/sys/netinet/ip.h Mon Feb 1 13:30:06 2010 (r203342) > : > +++ head/sys/netinet/ip.h Mon Feb 1 14:13:44 2010 (r203343) > : > @@ -48,11 +48,11 @@ > : > */ > : > struct ip { > : > #if BYTE_ORDER == LITTLE_ENDIAN > : > - u_int ip_hl:4, /* header length */ > : > + u_char ip_hl:4, /* header length */ > : > ip_v:4; /* version */ > : > #endif > : > #if BYTE_ORDER == BIG_ENDIAN > : > - u_int ip_v:4, /* version */ > : > + u_char ip_v:4, /* version */ > : > ip_hl:4; /* header length */ > : > #endif > : > u_char ip_tos; /* type of service */ > : > @@ -142,11 +142,11 @@ struct ip_timestamp { > : > u_char ipt_len; /* size of structure (variable) */ > : > u_char ipt_ptr; /* index of current entry */ > : > #if BYTE_ORDER == LITTLE_ENDIAN > : > - u_int ipt_flg:4, /* flags, see below */ > : > + u_char ipt_flg:4, /* flags, see below */ > : > ipt_oflw:4; /* overflow counter */ > : > #endif > : > #if BYTE_ORDER == BIG_ENDIAN > : > - u_int ipt_oflw:4, /* overflow counter */ > : > + u_char ipt_oflw:4, /* overflow counter */ > : > ipt_flg:4; /* flags, see below */ > : > #endif > : > union ipt_timestamp { > : > > : > : struct ip normally doesn't cause any problems, since although it > : doesn't > : contain any ints which would force its size to a multiple of 4 to > : satisyf alignment requirements, it happens to have size a multiple of > : 4 > : anyway (20). Thus gcc's bogus alignment for the struct doesn't change > : anything. The other compilers are apparently more broken. > : > : It is not easy to fix broken declarations in central headers like > : this. > : wollman tried to do it for some of the above in rev.1.7 (IP_VHL), but > : failed, and the attempt was axed in rev.1.20. > : > : Rev.1.20 also introduced related unportability, ugliness and > : pessimizations > : for struct ip -- it added the __packed directive. This was spelled > : unportably using __attribute__ ((); the unportability was fixed in > : 1.21. Using __packed results in all accesses to members of the struct > : being done as if the struct has alignment 1. On i386, this is only > : slightly slower for accessing the shorts in struct ip, but on machines > : with strict alignment requirements the compiler has to generate slower > : code to access the shorts a byte at a time and there may be atomicity > : issues. > : > : Rev.1.30 attempted to fix this by also adding the __aligned(4) > : attribute. > : I haven't checked that this works. It adds additional unportability > : and > : ugliness. > : > : Apparently the unportable ugliness of __packed and __aligned is not > : enough > : to actually work for the other compilers. If __packed is unavailable, > : then it should cause a syntax error. If it is available, then it > : should > : actually work, and actually working involves not padding the > : bit-fields. > : Then __aligned(4) is needed less strongly to clean up the mess from > : using > : __packed. > : > : > Modified: head/sys/netinet/tcp.h > : > ============================================================================== > : > --- head/sys/netinet/tcp.h Mon Feb 1 13:30:06 2010 (r203342) > : > +++ head/sys/netinet/tcp.h Mon Feb 1 14:13:44 2010 (r203343) > : > @@ -52,11 +52,11 @@ struct tcphdr { > : > tcp_seq th_seq; /* sequence number */ > : > tcp_seq th_ack; /* acknowledgement number */ > : > #if BYTE_ORDER == LITTLE_ENDIAN > : > - u_int th_x2:4, /* (unused) */ > : > + u_char th_x2:4, /* (unused) */ > : > th_off:4; /* data offset */ > : > #endif > : > #if BYTE_ORDER == BIG_ENDIAN > : > - u_int th_off:4, /* data offset */ > : > + u_char th_off:4, /* data offset */ > : > th_x2:4; /* (unused) */ > : > #endif > : > u_char th_flags; > : > > : > : struct tcphdr has some uint32_t's in it, so again the bogus gcc > : alignment > : has no effect (but things need to be packed even more carefully to > : avoid > : padding; fortunately, the wire layout happens to align everything). > : > : struct tcphdr hasn't been affected by the __packed/__aligned(4) > : unportable ugliness. > : > : Bruce > :
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100201183923.GA32901>