lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] Struct packing/alignment problems


From: Timmy Brolin
Subject: Re: [lwip-users] Struct packing/alignment problems
Date: Tue, 04 May 2004 18:54:45 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)

K.J. Mansley wrote:

On Tue, 2004-05-04 at 15:41, address@hidden wrote:
On Tue, 2004-05-04 at 01:04, Timmy Brolin wrote:
Mandatory alignment would render all those STRUCT_PACK macros unnecessary, resulting in cleaner code, and significantly increased portability (ANSI C conformant, no alignment problem, and no need to define architecture specific struct packing macros)
Padding of the start of the struct does not guarantee the alignment of
subsequent elements in that struct, so the packing is still required.

Kieran
Oh but it does.
The fields in the IP and TCP headers are properly aligned relative to the start of the headers by design. The problem is that the ethernet header is 14 bytes which is not a factor of four, so the starting address of the subsequent IP and TCP structs become unaligned. A compiler normaly fix struct alignment problems by silently inserting padding between the fields in the struct (this is of course not acceptable). In order to keep the compiler from doing so, there are struct packing compiler directives in the lwip code. Theese compiler directives tell the compiler to pack the structs even if they are unaligned. Not all compilers and processors support this, it is not ANSI C, and the implementation is highly compiler specific.

By padding the ethernet header to 16 bytes, we ensure that the IP and TCP structs are correctly aligned. And since there are no alignment problems, the compiler will not add any padding. Thus, we don't need the struct packing directives.

There are two issues here which you seem to be confusing:

1) Ensuring that the IP header is aligned on a 32bit boundary.  The
standard way to do this is to reserve two bytes before the ethernet
header (if you happen to be using Ethernet) so that the following IP
header is 32 bit aligned.  I think we agree on this: you certainly have
no argument from me that this is a good thing, and I thought the
Ethernet driver already supported this.

2) Ensuring that the structs do not have gaps between fields.  This is
independent of anything to do with Ethernet having 14 byte headers, or
the alignment of the network headers.  It is simply ensuring that all
the elements are sequential in memory with no gaps.  Just making sure
the start of the struct is 32bit aligned will not guarantee this.  On
64bit alpha architectures for example I've run into problems where a
non-packed struct would have padding inserted *in the middle* of the
struct, as the compiler could access it more efficiently that way.  I
know the GCC pack directives are not ANSI C, but there is no other way
that I am aware of, other than not using structs at all, to ensure this.
That is why we use the packed struct directives.  If you know of an
alternative that is more standards compliant, please let us know.

Hope that clarifies the reasons why we need both padding and packing!

Kieran

The two issues are not independent. Simple proof: A struct containing a single int32 will be padded by the compiler if the start address of the struct is not aligned to 4 bytes, but not if the start adress is aligned to 4 bytes.

It isn't permitted for a type to have an alignment requirement larger than its own size. This is a ANSI requirement. And, I am fairly sure I read somewhere that struct fields are padded to their natural alignment. Not entirely sure on the ANSI take on this one. Theese two basic rules would guarantee that there will be no gaps inserted into the IP and TCP structs, assuming the start address of the IP struct is aligned to 4 bytes.

I can't say much about your alpha 64 example since I have not seen it, but generally the compiler will add padding between fields if field alignment problems occur.
For example:
{
int16 fielda;
int32 fieldb;
int16 fieldc;
}
The compiler will add two bytes of padding between fielda and fieldb to ensure 4 byte alignment of fieldb.

Timmy





reply via email to

[Prev in Thread] Current Thread [Next in Thread]