I'm getting hardfault with following code using both 9-2020-q2-update and 8-2019-q3-update arm-none-eabi toolchains:
#define ALIGNMENT ( 1 )
#pragma pack(push, ALIGNMENT)
typedef struct a {
int16_t i16;
uint64_t u64;
} a_t;
#pragma pack(pop)
[...]
// s is passed as void*
((a_t *)s)->u64 = (uint64_t)-1;
((a_t *)s)->i16 = 0;
With an alignment defined as macro in #pragma pack gcc generates following code with -O0:
217 ((a_t *) s)->u64 = (uint64_t)-1;
08043654: ldr r1, [r7, #16]
08043656: mov.w r2, #4294967295
0804365a: mov.w r3, #4294967295
0804365e: strd r2, r3, [r1, #8]
218 ((a_t *) s)->i16 = 0;
08043662: ldr r3, [r7, #16]
08043664: movs r2, #0
08043666: strh r2, [r3, #0]
r7 contains s value, which is not aligned to 4-byte boundary. strd generates hardfault.
Correct assembly is generated when i use #pragma pack(push, 1):
217 ((a_t *) s)->u64 = (uint64_t)-1;
08043918: ldr r3, [r7, #16]
0804391a: adds r3, #2
0804391c: mov.w r2, #4294967295
08043920: strb r2, [r3, #0]
08043922: mov.w r2, #4294967295
08043926: strb r2, [r3, #1]
08043928: mov.w r2, #4294967295
0804392c: strb r2, [r3, #2]
0804392e: mov.w r2, #4294967295
08043932: strb r2, [r3, #3]
08043934: mov.w r2, #4294967295
08043938: strb r2, [r3, #4]
0804393a: mov.w r2, #4294967295
0804393e: strb r2, [r3, #5]
08043940: mov.w r2, #4294967295
08043944: strb r2, [r3, #6]
08043946: mov.w r2, #4294967295
0804394a: strb r2, [r3, #7]
218 ((a_t *) s)->i16 = 0;
0804394c: ldr r3, [r7, #16]
0804394e: movs r2, #0
08043950: strb r2, [r3, #0]
08043952: movs r2, #0
08043954: strb r2, [r3, #1]
Is there any way to correctly pass alignment defined as macro to #pragma pack? I've got packed struct definitions scattered around the whole codebase. There are some memory constrained platforms, where i want to align them to one-byte boundary and some platforms, where it isn't so important, and performance gains would be nice. It would be convenient to have alignment defined once and used in all pragmas.
pragma pushand not gcc syntax__attribute__((__aligned__? - KamilCuk