MSPM33-SDK: Sizeof for structure and alignment

Part Number: MSPM33-SDK
Other Parts Discussed in Thread: MSPM33C321A

Hello,

I'm working on MSPM33C321A on CCS, I have declared a structure where inside there are other structures, like this:

typedef struct
{
  sStructure1                 S_struct1;
  uint16_t                      u16Data1;
  sStructure2                 S_struct2;
  sStructure3                 S_struct3;
  sStructure4                 S_struct4;
  sStructure5                 S_struct5;
  sStructure6                 S_struct6;
  sStructure7                 S_struct7;
  uint16_t                      u16Data2;
}MainStructure;

I check that:

sizeof(MainStructure) is not equal to sizeof (sStructure1) + sizeof(u16Data1) + sizeof (sStructure2) + sizeof (sStructure3) + .... + sizeof (sStructure7)  + sizeof(u16Data2)

But if the int16_t are moved by uint32_t, I have :

sizeof(MainStructure) = sizeof (sStructure1) + sizeof(u32Data1) + sizeof (sStructure2) + sizeof (sStructure3) + .... + sizeof (sStructure7)  + sizeof(u32Data2)

 

I checked in linker file, and the alignment are declare on 16 bits

image.png

Could you tell me if it possible to fix this issue ?

Thanks

 

 

  • Hello Sebastian, 

    The behavior you are observing is expected and caused by compiler structure padding/alignment rather than the linker palign() setting. In C, the compiler may insert padding bytes between structure members so that each member starts at an address satisfying its alignment requirement. For example, if a uint16_t is followed by a structure requiring 4-byte alignment, two padding bytes may be inserted after the uint16_t. This can then cause the size of MainStructure to be larger. When 16 is replaced by 32, no padding is necessary hence the right size will be observed. 

    Regards,

    Benedict Jojo

  • Hello Arthur,

    ok for that but why the compiler added paddings if it is aligned at 16bits ?

    If it was a 8 bits, I understood.

    How avoid to add padding, and the data are stored address by address ?

  • Hi Sebastien,

    The compiler behavior should work as follows:

    • The alignment constraint associated with the MainStructure is the maximum alignment imposed by each of the MainStructure members
    • If the MainStructure alignment constraint, x, is >= y in palign(y), then the address where MainStructure is defined will be aligned to a x-byte boundary, note that the size of the section in which MainStructure is defined will be padded to a multiple of y-bytes due to the palign(y)
    • If the MainStructure alignment constraint, x, is < y in palign(y), then the address  where MainStructure is defined will be aligned to a y-byte boundary, again note that the size of the rection in which MainStructure is defind will be padded to a multiple of y-bytes due to the palign(y)
    • Depending on the alignment constraints on each of the members of MainStructure, there may be alignment padding between the members
    • A palign(x) operator instructs the linker to both align a section to an x-byte boundary and pad the size of the section to a multiple of x-bytes

    Consider the following example source file, tryme.c:

    #include <stdio.h>

    struct {
      char c1;
      short s2;
      int i3;
      float f4;
      double d5;
      short s6;
      char c7;
    } MainStruct = { 10, 20, 30, 40.5, 50.125, 60, 70 };


    int main() {
      printf("MainStruct.c7: %d\n", (int)MainStruct.c7);
      return 0;
    }

    When this is compiled with "tiarmclang -mcpu=cortex-m33 -S tryme.c," the relevant compiler generated assembly looks like this:

            .section .text.main,"ax",%progbits
            .globl main
            .p2align 1
            .code 16
            .thumb_func

    main: 
            push {r7, lr}
            sub sp, #8
            movs r0, #0
            str r0, [sp]
            str r0, [sp, #4]
            movw r0, :lower16:MainStruct
            movt r0, :upper16:MainStruct
            ldrb r1, [r0, #26]
            movw r0, :lower16:.L.str
            movt r0, :upper16:.L.str
            bl printf
            ldr r0, [sp] @ 4-byte Reload
            add sp, #8
            pop {r7, pc}

    ...

            .section .data.MainStruct,"aw",%progbits
            .globl MainStruct
            .p2align 3, 0x0
    MainStruct:
            .byte 10 @ 0xa
            .byte 0 @ 0x0                               <- pad 1-byte
            .short 20 @ 0x14                          <- align to 2-byte boundary
            .long 30 @ 0x1e
            .long 0x42220000 @ float 40.5
            .zero 4                                          <- pad 4-bytes
            .long 0 @ double 50.125              <- align to 8-byte boundary
            .long 1078530048
            .short 60 @ 0x3c 

            .byte 70 @ 0x46

            .zero 5                                          <- pad struct to the next 8-byte boundary
            .size MainStruct, 32

    So the sizeof "MainStruct" in this example is 32 bytes and is != sizeof(char) + sizeof(short) etc

    The size of the struct is padded to a multiple of its alignment by default. You can avoid alignment padding between struct members by applying a "packed" attribute to the struct, like so:

             struct __attribute__((packed)) foo {

               ...

             } SSS;

    Going back to the example, suppose in the linker command file we have the following:

    MEMORY
    {
    ...
    S_MEM : org = 0x20200001 len = 0x100000
    }

    SECTIONS
    {
       ...

       .mainStruct : { tryme.o(.data) } palign(16) > S_MEM

       ...
    }

    S_MEM starts on an unaligned address. The palign(16) will force the definition of "MainStruct" to start on a 16-byte boundary even though the minimum alignment requirement for the struct is on an 8-byte boundary. Furthermore, the size of the .mainStruct section will be padded to a multiple of 16 bytes.

    This is reflected in the content of the map file:

    .mainStruct
     *        0     20200010 00000020 UNINITIALIZED
                       20200010 00000020 tryme.o (.data.MainStruct)

    If you want to avoid the padding caused by the palign(x) operator, you can use the align(x) operator instead.

    Hope this helps. Please reply if you have further questions or need further clarification.

    Best Regards,

    Todd Snider