0

我使用 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 packgcc 中将对齐定义为宏生成以下代码-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?我在整个代码库中都有打包的结构定义。有一些内存受限的平台,我想将它们对齐到一字节边界和一些平台,它不是那么重要,性能提升会很好。将对齐定义一次并在所有 pragma 中使用会很方便。

4

1 回答 1

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)]]属性。

于 2020-07-09T12:03:11.173 回答