Выравнивание, переданное как макрос в #pragma pack(push,ALIGNMENT), приводит к возникновению кода сбои
Я получаю жесткий сбой со следующим кодом, используя инструменты 9-2020-q2-update и 8-2019-q3-update arm-none-eabi:
#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;
С выравниванием, определенным как макрос в #pragma pack
gcc генерирует следующий код с -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
содержит s
значение, которое не выровнено по 4-байтовой границе. strd
порождает отказ.
Правильная сборка создается, когда я использую #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]
Есть ли способ правильно передать выравнивание, определенное как макрос, в #pragma pack
? У меня есть упакованные определения структур, разбросанные по всей кодовой базе. Есть некоторые платформы с ограничением памяти, где я хочу выровнять их по однобайтовой границе, и некоторые платформы, где это не так важно, и прирост производительности был бы неплохим. Было бы удобно, если бы выравнивание было определено один раз и использовалось во всех прагмах.
1 ответ
Просто используйте правильное расширение gcc attribute
:
#define ALIGNMENT 1
typedef struct a {
int16_t i16;
uint64_t u64;
} a_t __attribute__((__aligned__(ALIGNMENT)));
#pragma pack(push
- это синтаксис, который gcc сохраняет для совместимости с msvc. Предпочитайте не использовать его с gcc.
В новейшем стандарте C синтаксис атрибутов стандартизируется. С arm-none-eabi-gcc10.1 с-std=c2x
ты можешь использовать [[gnu::aligned(ALIGNMENT)]]
атрибут.