2024-03-04 09:57 PM - edited 2024-03-04 10:27 PM
Hi Community,
I have a bitfield arrangement for one of the driver files which is a 32-bit value. While debugging I was not able to figure out how it is being stored in the register. The bit order and endianness are not always guaranteed in structs and bit fields but I want to have a fair knowledge on how it is being stored.
Bit field arrangement
typedef union
{
uint32_t value;
struct
{
uint8_t data_1 : 4;
uint8_t data_2 : 3;
uint8_t data_3 : 4;
uint8_t data_4 : 2;
uint8_t data_5 : 1;
uint8_t data_6 : 1;
uint8_t data_7 : 2;
const uint8_t data_8 : 3;
} field;
} reg_t;
If I assign a value to fields of data like below the expected 32-bit value data.field.value is 0x88372.
reg_t data = {.field.data_8 = 4};
data.field.data_1 = 2;
data.field.data_2 = 7;
data.field.data_3 = 6;
data.field.data_7 = 1;
But I am getting 0x110672 why?
Solved! Go to Solution.
2024-03-05 05:48 AM
I suspect it doesn't want to split data_3 across different uint8_t values in memory.
Making all the fields uint32_t instead of uint8_t will give you what you want.
2024-03-05 05:48 AM
I suspect it doesn't want to split data_3 across different uint8_t values in memory.
Making all the fields uint32_t instead of uint8_t will give you what you want.
2024-03-05 05:56 AM - edited 2024-03-05 07:29 AM
Interesting.
How does the ARM / compiler handle byte variables within the memory when the linker file declares it as ALIGN(4) ?
2024-03-05 07:22 AM
Bitfield arrangement is compiler-specific.
In gcc, use __attribute__((packed)) struct, to enforce bitfields layout.
JW
2024-03-05 07:39 AM
Now change the type of fields to int16_t and you'll get yet another value.
Linker? The compiler cannot know how the linker aligns sections, this occurs later at link time.
2024-03-05 08:01 AM
> In gcc, use __attribute__((packed)) struct, to enforce bitfields layout.
I tried this, it had no effect on the layout. Compiler still forced data_3 to be on a new byte.
2024-03-05 08:44 AM - edited 2024-03-05 08:53 AM
This is an intricate issue and many things can go wrong - there are global settings influencing bitfield packing, maybe alignment of the struct's allocation influences that too, gcc version is a factor, and there may even be switches/configuration upon gcc compilation influencing that. For example, https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-packed-variable-attribute says:
Note: The 4.1, 4.2 and 4.3 series of GCC ignore the packed attribute on bit-fields of type char. This has been fixed in GCC 4.4 but the change can lead to differences in the structure layout. See the documentation of -Wpacked-bitfield-compat for more information.
There are also "funny" options which influence bitfield packing ordering in a very subtle (but of course important when it comes to interoperability) ways, for example this x86-specific option: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mms-bitfields (guess why do I know about it).
My gcc setup (5.4.1 20160609 from launchpad - and again I don't know what are all the factors impacting this) results in 0x110672 without packed attribute, and 0x88372 with it.
JW
PS. The "legal" framework for gcc is https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html (Whether a bit-field can straddle a storage-unit boundary ) and in relevant portion of ARM ABI (AAPCS32) the note at the end of chapter 8.1.7.1 Bit-fields no larger than their container
2024-03-05 08:13 PM
@TDK that was a good observation that helped me a lot. Thank you.
2024-03-05 08:18 PM
@waclawek.jan thanks for pointing out resources to have a look at. It was a great learning for me.
2024-03-05 08:19 PM
@Pavel A. Yes, it does.