1.2.2. Unaligned fields in structures

In the same way that global variables are located on their natural size boundary, so are the fields in a structure. This means that the compiler often has to insert padding between fields to ensure that fields are aligned. The compiler generates the following remark when it inserts padding between fields in a structure:


#1301-D: padding inserted in struct mystruct

The compiler also inserts padding at the end of a structure to ensure that the structure as a whole is aligned, and generates the following remark:


#2530-D: padding added to end of struct mystruct

Use the --remarks compiler option to display remarks.

Sometimes, you might not want the compiler to insert padding. You can use the __packed qualifier to create structures without padding between fields. These structures require unaligned accesses.

If the ARM compiler knows the alignment of a particular structure, it can work out whether or not the fields it is accessing are aligned within a packed structure. In these cases, the compiler carries out the more efficient aligned word or halfword accesses, where possible. Otherwise, the compiler uses multiple aligned memory accesses (LDR, STR, LDM, and STM) combined with fixed shifting and masking to access the correct bytes in memory.

Whether these accesses to unaligned elements are done inline or by calling a function is controlled by using the compiler options -Ospace (default, calls a function) and -Otime (do unaligned access inline).

For example:

  1. Create a file foo.c that contains:

    __packed struct mystruct {
        int aligned_i;
        short aligned_s;
        int unaligned_i;
    };
    struct mystruct S1;
    
    int foo (int a, short b)
    {
        S1.aligned_i=a;
        S1.aligned_s=b;
        return S1.unaligned_i;
    }
    
  2. Compile this using armcc -c -Otime foo.c. The code produced is:

    MOV      r2,r0
    LDR      r0,|L1.84|
    MOV      r12,r2,LSR #8
    STRB     r2,[r0,#0]
    STRB     r12,[r0,#1]
    MOV      r12,r2,LSR #16
    STRB     r12,[r0,#2]
    MOV      r12,r2,LSR #24
    STRB     r12,[r0,#3]
    MOV      r12,r1,LSR #8
    STRB     r1,[r0,#4]
    STRB     r12,[r0,#5]
    ADD      r0,r0,#6
    BIC      r3,r0,#3
    AND      r0,r0,#3
    LDMIA    r3,{r3,r12}
    MOV      r0,r0,LSL #3
    MOV      r3,r3,LSR r0
    RSB      r0,r0,#0x20
    ORR      r0,r3,r12,LSL r0
    BX       lr
    

    However, you can give the compiler more information to enable it to know which fields are aligned and which are not. To do this you must declare non-aligned fields as __packed, and remove the __packed attribute from the struct itself.

    This is the recommended approach, and the only way of guaranteeing fast access to naturally aligned members within the struct.

    It is also clearer which fields are non-aligned, but care is needed when adding or deleting fields from the struct.

  3. Now modify the definition of the structure in foo.c to:

    struct mystruct {
        int aligned_i;
        short aligned_s;
        __packed int unaligned_i;
    };
    struct mystruct S1;
    
  4. Compile foo.c and the following, more efficient code, is generated:

    MOV      r2,r0
    LDR      r0,|L1.32|
    STR      r2,[r0,#0]
    STRH     r1,[r0,#4]
    LDMIB    r0,{r3,r12}
    MOV      r0,r3,LSR #16
    ORR      r0,r0,r12,LSL #16
    BX       lr
    

The same principle applies to unions. Use the __packed attribute on the components of the union that will be unaligned in memory.

Note

Any __packed object accessed through a pointer has unknown alignment, even packed structures.

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203G
Non-Confidential