1

运行 Atmel Studio 及其提供的 gcc 6.3.1 为 Atmel/Microchip SAMV70 (ARM Cortex-M7) 芯片构建固件。我有使用 . 将 4 字节输入数组与 4 字节本地数组进行比较的代码memcmp()。当编译-O0为禁用优化时,它可以正常工作。当编译-Os为优化大小或使用-O3最大优化时,编译器将memcmp()调用替换为直接的 4 字节比较(通过检查反汇编进行验证)。不幸的是,优化有时还会将本地 4 字节数组移动到未对齐的起始地址,因此虽然可以正常工作,但由于未对齐访问 memcmp(),直接比较会触发 a 。HardFault

在我看来,这是 100% 的编译器优化错误(可能是 gcc,可能是 Atmel 添加的),但我坚持使用提供的编译器,因此无法选择更新。所以这是我的实际问题:有没有办法保持优化启用但禁用此特定优化?否则,我会被迫强制本地 4 字节数组对齐 4 字节或寻找其他解决方法。

编译器版本: gcc version 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437] (Atmel build: 508)

这是一个可能触发故障的示例函数:

bool example(uint8_t *input_data)
{
    uint8_t local_data[4] = { 0x00, 0x01, 0x02, 0x03 };

    return (memcmp(input_data, local_data, 4) == 0);
}

我的代码总是以 4 字节对齐的方式传递,input_data所以这不是问题,但编译器优化再一次认为这是理所当然的,这是一种不好的形式。

4

1 回答 1

3

回答我自己的问题,因为尤金没有发布官方答案:

gcc ARM 选项

默认情况下,所有 pre-ARMv6、所有 ARMv6-M 和 ARMv8-M Baseline 架构都禁用未对齐访问,并为所有其他架构启用。

这意味着 ARMv7-M默认允许未对齐访问。事实证明这是有道理的,因为来自ARMv7-M 架构参考手册

以下数据访问支持未对齐寻址,并且仅在 CCR.UNALIGN_TRP 位设置为 1 时生成对齐错误,请参见配置和控制寄存器:

• 非半字对齐的LDR{S}H{T} 和STRH{T}。

• 非半字对齐的TBH。

• 非字对齐 LDR{T} 和 STR{T}。

这意味着 ARMv7-M 支持一组有限的未对齐访问。 但是,它不支持所有未对齐的访问:

以下数据访问总是会产生对齐错误:

• 非半字对齐的LDREXH 和STREXH。

• 非字对齐LDREX 和STREX。

• 非字对齐LDRD、LDMIA、LDDMB、POP、LDC、VLDR、VLDM 和VPOP。

• 非字对齐的STRD、STMIA、STMDB、PUSH、STC、VSTR、VSTM 和VPUSH。

并且:

对强有序和设备内存类型的访问必须始终自然对齐

所以这是促使我提出最初问题的失败条件:

  1. 启用优化的 gcc 将 4 字节替换memcmp()为直接比较,这默认允许的,因为默认情况下允许未对齐的访问。所以这不是编译器错误。
  2. 包含数据的闪存区域memcmp()位于声明的 MPU 段中Strongly Ordered支持未对齐访问。因此,当memcmp()被直接比较替换,并且数据落在未对齐的地址上时,比较触发了HardFault.

Eugene 在他最初的评论中得到正确的修复是添加-mno-unaligned-access到编译器选项中。在我的情况下,这仍然允许编译器用memcmp()直接的 4 字节比较替换 ,但它也强制数据为 4 字节对齐,允许比较成功而不会触发故障条件。

于 2020-03-02T21:11:58.827 回答