gcc packed structs?
Re:gcc packed structs?
BTW, just a follow up, bitfields are nice and all, but they have a downside..the way they are implemented is left up to the compiler writters, it is implementation defined.
this means that the order the fields go (LSB first or MSB first?) and in fact the order they are placed can change between compilers (or even compiler versions technically speaking...though that's highly unlikely).
like i said before, if you are sticking with one compiler it really doesn't make a difference, but if you are worried about portability...stay away
proxy
this means that the order the fields go (LSB first or MSB first?) and in fact the order they are placed can change between compilers (or even compiler versions technically speaking...though that's highly unlikely).
like i said before, if you are sticking with one compiler it really doesn't make a difference, but if you are worried about portability...stay away
proxy
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:gcc packed structs?
Well, of course bitfields are architecture-dependent ... just take a look at PowerPC processors which are big-endian(?) while Intel processors are little-endian (it may be the contrary: i always mess up those two terms).
One will store the lowest bits of 0x12345678 first and the other will store the highest bits first. You shouldn't expect the same compiler to produce a bit-to-bit match of a bitfield made of 0x12345678 ... The very same way you shouldn't expect union { char c[4]; int; } to be portable across those architectures...
However, you need "trustable" bitfields mainly for architecture-dependent things like IDT, page table entries, etc. So it doesn't harm if those pieces of code are not portable.
Those architecture-dependent files are certainly full of asm(...) definitions aswell, so who cares if they're not portable to another compiler family ... If you really need another compiler to support your kernel (hum, ever tried to compile Linux kernel with msvc++ ?), you'll have to port the architecture/platform dependent code, including the bitfields definition, asm commands like "setPDBR() or FlushTranslationLookasideBuffer(), enable() and disable()" ...
Just bind those "dependent" parts to a well known place and try hard to avoid architecture/environment dependent stuff elsewhere.
The advantage of bitfields in that domain is that the rest of the text will use a *name* to access a part of the member. Whether arch/i386/stuff.h declared
while arch/ppc/stuff.h declared
to match the same pattern will be transparent to code that performs
v.major >= requrired.major
One will store the lowest bits of 0x12345678 first and the other will store the highest bits first. You shouldn't expect the same compiler to produce a bit-to-bit match of a bitfield made of 0x12345678 ... The very same way you shouldn't expect union { char c[4]; int; } to be portable across those architectures...
However, you need "trustable" bitfields mainly for architecture-dependent things like IDT, page table entries, etc. So it doesn't harm if those pieces of code are not portable.
Those architecture-dependent files are certainly full of asm(...) definitions aswell, so who cares if they're not portable to another compiler family ... If you really need another compiler to support your kernel (hum, ever tried to compile Linux kernel with msvc++ ?), you'll have to port the architecture/platform dependent code, including the bitfields definition, asm commands like "setPDBR() or FlushTranslationLookasideBuffer(), enable() and disable()" ...
Just bind those "dependent" parts to a well known place and try hard to avoid architecture/environment dependent stuff elsewhere.
The advantage of bitfields in that domain is that the rest of the text will use a *name* to access a part of the member. Whether arch/i386/stuff.h declared
Code: Select all
struct version {
int major:10;
int minor:10;
int revision:10;
int :2;
};
Code: Select all
struct version {
int :2;
int revision:10;
int minor:10;
int major:10;
};
v.major >= requrired.major
Re:gcc packed structs?
Absolutely correct. Note that some PowerPC's (as well as some other CPU architectures) have the ability to switch into little-endian mode...Pype.Clicker wrote: Well, of course bitfields are architecture-dependent ... just take a look at PowerPC processors which are big-endian(?) while Intel processors are little-endian (it may be the contrary: i always mess up those two terms).
Every good solution is obvious once you've found it.
Re:gcc packed structs?
Pype, unfortunately you fell into a trap there:
on PPC it will end up being more like this:
this is because the byte swapping will occur on byte boundaries (not field boundaries...resulting in the fields being broken up.
think of it this way...if you cast that structure to a 32-bit unsigned int, then byte swap it...where will the bites end up...not simply the reverse fields...
proxy
is NOT correct! (well the first one is probably) but the second is not the equivalent of byte swapping....if your fields were all less that 8 bits then it would be true to jsut reverse the order...but in this case (since they are 10) you will have major problems...while arch/ppc/stuff.h declaredCode: Select all
struct version { int major:10; int minor:10; int revision:10; int :2; };
Code: Select all
struct version { int :2; int revision:10; int minor:10; int major:10; };
on PPC it will end up being more like this:
Code: Select all
struct version {
int major_2: 4
int major_1: 4
int minor_2: 4
int revision_2: 4;
int minor_1: 4
int :2;
int revision_1: 6;
};
this is because the byte swapping will occur on byte boundaries (not field boundaries...resulting in the fields being broken up.
think of it this way...if you cast that structure to a 32-bit unsigned int, then byte swap it...where will the bites end up...not simply the reverse fields...
proxy
Re:gcc packed structs?
Code: Select all
struct version {
int :2;
int revision:10;
int minor:10;
int major:10;
};
Code: Select all
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| pad | major | minor | revision |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
| pad | major(9-4) | |major(3-0) |minor(9-6) | | minor(5-0) |r9-8 | | rev(7-0) |
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
| rev(7-0) | | minor(5-0) |r9-8 | |major(3-0) |minor(9-6) | | pad | major(9-4) |
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| rev2(7-0) | minor(5-0) | r9-8|major(3-0) |minor(9-6) | pad | major(9-4) |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Code: Select all
struct version {
int major_1: 6;
int :2;
int minor_1: 4;
int major_2: 4;
int revision_1: 2;
int minor_2: 6;
int revision_2: 8;
};
Re:gcc packed structs?
@ proxy:
As far as I understood it, Pype didn't try to address byte swapping in his example, but rather show how named bitfields allow further source code to handle the individual fields transparently.
As far as I understood it, Pype didn't try to address byte swapping in his example, but rather show how named bitfields allow further source code to handle the individual fields transparently.
Every good solution is obvious once you've found it.
Re:gcc packed structs?
@Candy yea, yours seems to be just about on the money I knew mine wasn't quite right, but I figured it was enough to demonstrate the fault.
@Solar well It seemed to me that he was trying to show how bitfields can be handled when porting to a opposite endian system (such as PPC) and frankly his example was very wrong. This is one of the primary reasons why bitfields are "non-portable" the moment you use them. As I said earlier, if you are sticking to the same compiler/arch, well it really doesn't matter...but if you are worried about portability to some extent (as the poster indicated) then bitfields are pretty much a bad option, it introduces too many possible "oops". In fact, I've had issues with poirting from x86 to Solaris where the bitfields didn't end up stricly byteswaped, but byteswapped, then reversed (so high and low bytes were in same spot but middle two bytes seemed to be revered..it was bizzar).
proxy
@Solar well It seemed to me that he was trying to show how bitfields can be handled when porting to a opposite endian system (such as PPC) and frankly his example was very wrong. This is one of the primary reasons why bitfields are "non-portable" the moment you use them. As I said earlier, if you are sticking to the same compiler/arch, well it really doesn't matter...but if you are worried about portability to some extent (as the poster indicated) then bitfields are pretty much a bad option, it introduces too many possible "oops". In fact, I've had issues with poirting from x86 to Solaris where the bitfields didn't end up stricly byteswaped, but byteswapped, then reversed (so high and low bytes were in same spot but middle two bytes seemed to be revered..it was bizzar).
proxy
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:gcc packed structs?
i was certainly not trying to show a bit-to-bit compatible 'version' that works on both i386 and ppc architecture ... so Solar was right though the others were rightfully spotting a possible trouble that someone who trust too quickly the stuff.h i submitted could encounter
If you need complex bitfields (not trivially mapping on single bytes) to be bit-to-bit compatible (for instance because they're stored in files or exchanged across network) it is certainly better to have an "endianness convertion" first on the words and *then* applying the 'local' bitfield ... but even that is not guaranteed to work :-/
If you need complex bitfields (not trivially mapping on single bytes) to be bit-to-bit compatible (for instance because they're stored in files or exchanged across network) it is certainly better to have an "endianness convertion" first on the words and *then* applying the 'local' bitfield ... but even that is not guaranteed to work :-/