Aligned access to packed struct

Asked by Jonathan Dumaresq

Hi,

I observe a problem with aligned access on M0. I try both gcc version with the same problem. (4.6q4 and 4.7u1).

I get an Hardfault with this code.

------------------------------------------------------------------------------------------------------------------------------
typedef struct Struct_HdrPrefix{
 uint8_t Prefix;
 uint16_t Type;
 uint16_t Size;
}__attribute((__packed__))Struct_HdrPrefix;

volatile Struct_HdrPrefix test;
volatile Struct_HdrPrefix test1;

int main(void)
{
 test.Type = 0;
 while(1)
  __asm("nop");
}

----------------------------------------------------------------------------------------------------------------------

Compile line

arm-none-eabi-gcc -DPRELOADER -DSTM32F0X_MD -DSTM32F0XX -I"C:\projects\MICR-0805\Firmware\stm32_workspace\TestPacked_M0\INC" -Os -ffunction-sections -fdata-sections -Wall -Wa,-adhlns="SRC/main.o.lst" -c -fmessage-length=0 -MMD -MP -MF"SRC/main.d" -MT"SRC/main.d" -mcpu=cortex-m0 -mthumb -g3 -gdwarf-2 -o "SRC/main.o" "../SRC/main.c"

If I don't optimise the code, everythig works well.

IF I use Os, I got the hardfault.

Should I add something in the compiling line or linking to not having the Hardfault. This look like an alignement problem.

regards

Jonathan

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Joey Ye
Solved:
Last query:
Last reply:
Revision history for this message
Tony Kao (c-tony) said :
#1

The struct is actually unaligned. Because you used the __packed__ attribute, the half-word Type member is offsetted on a byte boundary, whereas Cortex-M0 (ARMv6-M) only supports half-word boundary for half-word access. This results in a HardFault exception.

Remove the __packed__ attribute or rearrange the members so that they are aligned properly.

See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABFAIGG.html

Revision history for this message
Jonathan Dumaresq (jdumaresq) said :
#2

Hi,

I cannot restructure this because it's a communication structure. this is fixed.

On Keil, the instruction differs when the access is not aligned. Probably an byte access is done instead of halfword access.

The compiler should take care of this ?

Jonathan

Revision history for this message
Tony Kao (c-tony) said :
#3

I don't know if __attribute__((packed)) guarantees that gcc will emit the proper code to handle misaligned data members; the compiler manual states only that "the structure or union is placed to minimize the memory required". It appears that the compiler generates the "correct code" on all optimization levels other than -Os, so this may be a bug.

As a workaround, you can add padding to the beginning of the struct, like so:

typedef struct {
 uint8_t reserved0;
 uint8_t Prefix;
 uint16_t Type;
 uint16_t Size;
} Struct_HdrPrefix;

You can then offset the address by one byte when using memcpy or DMA to fill the struct. This guarantees proper alignment in a portable way (at least within the ARM world) at the same time ensuring that the members are "packed" together.

Hope this helps.

Revision history for this message
Jonathan Dumaresq (jdumaresq) said :
#4

Hi,

Gcc should be able to handle this from my point of view. gcc know that the struct is packed and he know also that the optimisation for the size is on also.

Where should I report this "bug" ?

thanx for your time

Jonathan

Revision history for this message
Best Joey Ye (jinyun-ye) said :
#5

Jonathan,

This looks like a bug in strict-volatile-bitfield plus packed attribute. I'm working on a bug report to GCC bugzilla.

Before it is fixed, it can be work around by -fno-strict-volatile-bitfields. Can you please try it?

Thanks - Joey

Revision history for this message
Joey Ye (jinyun-ye) said :
#6

Just opened a gcc bug at: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56997

Please follow that record for discussion and status update.

Thanks - Joey

Revision history for this message
Jonathan Dumaresq (jdumaresq) said :
#7

Hi Joey,

I will look at this. I let you know my result by towmorrow.

Jonathan

Revision history for this message
Jonathan Dumaresq (jdumaresq) said :
#8

Hi Joey,

This is solve the problem for me.

Thanx for your help, and I will follow the bug report on GCC.

Jonathan

Revision history for this message
Jonathan Dumaresq (jdumaresq) said :
#9

Thanks Joey Ye, that solved my question.

Revision history for this message
Nestor Lopez Casado (xnlopez) said :
#10

Hi Joey,

I encountered a similar issue:

#define MEMBER_SIZE(type, member) (sizeof(((type *) 0)->member))

typedef union
{
    struct
    {
        uint8_t RunTimer;
        uint8_t AltTab;
        uint8_t ForEver;
    } flags;
    uint32_t all;
} rtos_busyFlags_tu;
STATIC_ASSERT(MEMBER_SIZE(rtos_busyFlags_tu, all) == sizeof(rtos_busyFlags_tu));

volatile bool rtos_MainFlag;
volatile rtos_busyFlags_tu rtos_BusyFlags;

when compiled with:
CFLAGS := -mcpu=cortex-m0 -mthumb -mabi=aapcs --std=gnu99 -fpack-struct -O2 -Wall -gdwarf-2

From .map:
0x00000000200003f8 rtos_MainFlag
0x00000000200003fc rtos_BusyFlags
    rtos_BusyFlags.all = 0;
    45a6: 6004 str r4, [r0, #0]
    rtos_BusyFlags.flags.RunTimer = true;
    45a8: 7001 strb r1, [r0, #0]
    45aa: bd10 pop {r4, pc}
    45ac: 4805 ldr r0, [pc, #20] ; (45c4 <rtos_InitModule+0xb4>)
    45ae: e7f8 b.n 45a2 <rtos_InitModule+0x92>

when compiled with: (optimize for size)
CFLAGS := -mcpu=cortex-m0 -mthumb -mabi=aapcs --std=gnu99 -fpack-struct -Os -Wall -gdwarf-2

From .map
0x00000000200003d4 rtos_MainFlag
0x00000000200003d5 rtos_BusyFlags **** Not aligned on 32bits

So that rtos_BusyFlags is not aligned on 32 bits. The generated assembly hardfaults when accessing rtos_BusyFlags, like this:
    rtos_BusyFlags.all = 0;
    39a6: 4807 ldr r0, [pc, #28] ; (39c4 <rtos_InitModule+0x94>)
    39a8: 6802 ldr r2, [r0, #0]
    39aa: 6005 str r5, [r0, #0]
    rtos_BusyFlags.flags.RunTimer = true;
    39ac: 7004 strb r4, [r0, #0]
Hard faults at address 39a8, when accessing 0x200003d5 (rtos_BusyFlags)

So for the moment I'm using -O2, but I am really wondering if this is a bug. For some reason on the above mentioned bugzilla, none ever speaks about -Os vs -O2.

Any comments ?
Nestor.

Revision history for this message
Nestor Lopez Casado (xnlopez) said :
#11

Forgot to mention: gcc-arm-none-eabi-4_7-2013q1

Nestor.

Revision history for this message
Joey Ye (jinyun-ye) said :
#12

Nestor,

The GCC does work correctly when handling packed volatile structures. The
failed cases various from case to case and options to options. For this
case with -Os I can only say GCC happen to walk around the trap, and -O2
fall down.

It is the same issue and can be walk around by the same option, and should
be fixed by the same pending patch.

On Tue, Aug 13, 2013 at 7:26 PM, Nestor Lopez Casado <
<email address hidden>> wrote:

> Question #226405 on GCC ARM Embedded changed:
> https://answers.launchpad.net/gcc-arm-embedded/+question/226405
>
> Nestor Lopez Casado posted a new comment:
> Forgot to mention: gcc-arm-none-eabi-4_7-2013q1
>
> Nestor.
>
> --
> You received this question notification because you are an answer
> contact for GCC ARM Embedded.
>