Page 1 of 2

Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 10:17 am
by CocaCola
I've seen that in James Molloy's and Bran Friesen's tutorials, the GDT structures are defined as:

Code: Select all

struct gdt_entry
{
    unsigned short limit_low;
    unsigned short base_low;
    unsigned char base_middle;
    unsigned char access;
    unsigned char granularity;
    unsigned char base_high;
} __attribute__((packed));
My question is: what would be the problem in using bitfields? As in:

Code: Select all

struct gdt_entry
{
    unsigned int base_low   : 8;
    unsigned int type       : 4;
    unsigned int s          : 1;
    unsigned int dpl        : 2;
    unsigned int p          : 1;
    unsigned int seglimit   : 4;
    unsigned int avl        : 1;
    unsigned int l          : 1;
    unsigned int db         : 1;
    unsigned int g          : 1;
    unsigned int base_high  : 8;
} __attribute__((packed));
Are there any dangers to doing the above?

Re: Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 10:55 am
by bluemoon
The spec do not enforce bit fields to be packed, so its compiler specific.
Although you may supply attribute(pack), as soon as you put different bit-width entities it's legal for the compiler to put it on next accessible unit(ie. next byte boundary)

The compiler may also re-arrange the fields, and you can't enforce byte order on the memory storage.

So, as with all compiler-specific stuff, test with your compiler, if it worked you put the compiler into "verified list"

Re: Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 12:23 pm
by Antti

Code: Select all

sizeof(unsigned int) is assumed to be 4.

struct example_1 {
	unsigned int a : 16;   /* OK */
	unsigned int b : 8;    /* OK */
	unsigned int c : 4;    /* OK */
	unsigned int d : 4;    /* OK */
};

sizeof(struct example_1) is 4.

struct example_2 {
	unsigned int a : 16;   /* OK */
	unsigned int b : 15;   /* OK */
	unsigned int c : 2;    /* Undefined alignment */
	unsigned int d : 31;   /* Undefined alignment */
};

sizeof(struct example_2) is ??.
I would say* it works like that. Adjacent bit-fields are packed if they fit to the base type. It happens to be that your struct gdt_entry works as expected if sizeof(unsigned int) is 4. No need for having the packed attribute or anything. I admit that this is quite dangerous...

*(Not a fact)

Re: Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 2:03 pm
by CocaCola
Thank you for your replies.
bluemoon wrote:The compiler may also re-arrange the fields, and you can't enforce byte order on the memory storage.
C99 Standard 6.7.2.1/10 wrote:The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.
At this point it's very obvious to me that I can't go this path.

Re: Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 10:51 pm
by Antti
CocaCola wrote:At this point it's very obvious to me that I can't go this path.
I recommend you to avoid using bit-fields. However, it is not "very obvious" because of the statement you quoted. I do not know any reason why that particular struct gtd_entry would not work just like "it should" if your compiler is targeting to a little-endian-4-bytes-int target. This is most likely the case if using that struct at all. Not necessarily but...

This may be a little bit pedantic discussion but it is the best part of this forum.

Re: Bitfield for GDT structure?

Posted: Thu Apr 25, 2013 11:53 pm
by CocaCola
Antti wrote:I do not know any reason why that particular struct gtd_entry would not work just like "it should" if your compiler is targeting to a little-endian-4-bytes-int target.
Well, like bluemoon said the compiler could possibly rearrange the fields, regardless of whether or not the target is Little Endian with 32-bit int. If I misunderstood, tell me.

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 12:19 am
by Antti
CocaCola wrote:If I misunderstood, tell me.
You did not misunderstand. I just disagree with the reordering of fields. Normal structure members are not reordered (alignment padding happens) so I think reordering bit-fields is very illogical. Whether the "bit-field direction" is high-to-low or low-to-high is not same as random reordering.

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 12:31 am
by dozniak
Antti wrote:
CocaCola wrote:If I misunderstood, tell me.
You did not misunderstand. I just disagree with the reordering of fields. Normal structure members are not reordered (alignment padding happens) so I think reordering bit-fields is very illogical. Whether the "bit-field direction" is high-to-low or low-to-high is not same as random reordering.
But according to the standard a compiler reordering fields to be in the order of increasing field bit width or decreasing field name length is perfectly valid.

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 3:02 am
by bluemoon
CocaCola wrote:
Antti wrote:I do not know any reason why that particular struct gtd_entry would not work just like "it should" if your compiler is targeting to a little-endian-4-bytes-int target.
Well, like bluemoon said the compiler could possibly rearrange the fields, regardless of whether or not the target is Little Endian with 32-bit int. If I misunderstood, tell me.
That's why you should test (or assume...) your compiler for "compatibility" with your kernel, on compiler-specific stuffs (not only bit-fields).

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 4:03 am
by Antti
This is all I quickly found and I think it applies:
ISO/IEC 9899:TC2 Committee Draft wrote:An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
Whether the addressable storage unit is 1, 2, or 4 bytes, this particular struct should work like expected (little-endian, sizeof(unsigned int) == 4). This is quite an ideal struct because there are no bitfields that are more than 8 bits wide.

Code: Select all

struct gdt_entry                       (bytes)
{                                      1    2    4    ( x == "allocation")
    unsigned int base_low   : 8;       x    x    x
    unsigned int type       : 4;       x
    unsigned int s          : 1;
    unsigned int dpl        : 2;
    unsigned int p          : 1;
    unsigned int seglimit   : 4;       x    x
    unsigned int avl        : 1;
    unsigned int l          : 1;
    unsigned int db         : 1;
    unsigned int g          : 1;
    unsigned int base_high  : 8;       x
};
I admit that it is possible to find a loophole if some compiler wants aggressively to do so.

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 4:19 am
by Brendan
Antti wrote:This is all I quickly found and I think it applies:
ISO/IEC 9899:TC2 Committee Draft wrote:An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
Basically, every single thing about bitfields that could possibly be implementation defined actually is implementation defined.

For example; it's perfectly valid for a compiler to use a 4-byte unit and allocate the high bits first:

Code: Select all

struct gdt_entry 
{ 
    unsigned int base_low   : 8;  // Bits 0 to 7 of fourth byte (highest bits of first dword)
    unsigned int type       : 4;  // Bits 4 to 7 of third byte (next highest bits of first dword)
    unsigned int s          : 1;  // Bit 3 of third byte (next highest bits of first dword)
    unsigned int dpl        : 2;  // Bits 1 to 2 of third byte (next highest bits of first dword)
    unsigned int p          : 1;  // Bit 0 of third byte (next highest bits of first dword)
    unsigned int seglimit   : 4;  // Bits 4 to 7 of second byte (next highest bits of first dword)
    unsigned int avl        : 1;  // Bit 3 of second byte (next highest bits of first dword)
    unsigned int l          : 1;  // Bit 2 of second byte (next highest bits of first dword)
    unsigned int db         : 1;  // Bit 1 of second byte (next highest bits of first dword)
    unsigned int g          : 1;  // Bit 0 of second byte (next highest bits of first dword)
    unsigned int base_high  : 8;  // Bits 0 to 7 of eighth byte (highest bits of second dword)
};
If a specific layout is required; do it right and use your own shifts, masks, etc.


Cheers,

Brendan

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 5:56 am
by Antti

Code: Select all

unsigned int base_high  : 8;  // Bits 0 to 7 of eighth byte (highest bits of second dword)
I do not understand the last line. Was that intentional? base_high fits to a 4-byte unit. OK, perhaps this topic reached its end and I stop annoying everyone.

As a conclusion: one thing I liked to point out was that bit fields are not randomly reordered. In Brendan's example, bit fields are "next to each other" in a way they are declared. Whether the direction is "low-to-high" or reverse is a different thing. However, I would like understand the "The order of allocation of bit-fields within a unit" being implementation-defined because of little and big endian architectures. That would be logical reason for that statement. Yes, I was wrong. It is possible for a little-endian-targeted compiler to do the bit-field allocation in a "big-endian way."

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 6:35 am
by Love4Boobies
I did not read the whole thread but the compliant solution to this problem is serialization. If you find it makes your code more readable (usually the most important aspect of code!), you can use a structure and bit-fields for manipulation. You don't pass this structure directly to the hardware but instead pass it to a serialization routine that encodes it into a static array of bytes or a file; the latter may require more work with most compilers but it's not wrong since C files are really streams rather than files in a file system. The alternative is to work with the serialized data structure directly, giving up some readability.

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 6:48 am
by xenos
I'm wondering whether there are differences between bit fields in C and C++. I just looked up the current standards and the following is confusing me:
C11 6.7.2.1 11 wrote:An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
This is just what has been concluded in this thread. (Or does "order" in this context only mean LSB first / MSB first?) However,
C++11 9.6 2 wrote:A declaration for a bit-field that omits the identifier declares an unnamed bit-field. Unnamed bit-fields are not members and cannot be initialized. [ Note: An unnamed bit-field is useful for padding to conform to externally-imposed layouts. —end note ] As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the value of the constant-expression be equal to zero.
So in C++, bit fields should be "suitable" for externally-imposed layouts (such as bits in a GDT)? In the preceding paragraph it sounds like "implementation-defined" is used synonymously for "machine dependent":
C++11 9.6 1 wrote:Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. —end note ]
I guess otherwise the existence of "padding" fields would not make sense at all, if they could just be shifted to whatever place...

EDIT: Wow, my post must be really evil, since it's my 666. post here :D

Re: Bitfield for GDT structure?

Posted: Fri Apr 26, 2013 11:47 am
by sortie
bluemoon wrote:That's why you should test (or assume...) your compiler for "compatibility" with your kernel, on compiler-specific stuffs (not only bit-fields).
You should in no way be making guesses about what ABI-dependent choices your compiler makes. Your system should have a clearly-defined ABI and the compiler you use should know about it. That's why we set up real cross-compilers and OS-specific toolchains.