如何防止 Atmel Studio gcc 6.3.1 将 4 字节 memcmp() 优化为 4 字节直接比较?
How to prevent Atmel Studio gcc 6.3.1 from optimizing 4-byte memcmp() to a 4-byte direct comparison?
运行 Atmel Studio 及其提供的 gcc 6.3.1 为 Atmel/Microchip SAMV70 (ARM Cortex-M7) 芯片构建固件。我有使用 memcmp()
将 4 字节输入数组与 4 字节本地数组进行比较的代码。当使用 -O0
编译以禁用优化时,它工作正常。当使用 -Os
编译以优化大小或使用 -O3
进行最大优化时,编译器将 memcmp()
调用替换为直接 4 字节比较(通过检查反汇编进行验证)。不幸的是,优化有时也会将本地 4 字节数组移动到未对齐的起始地址,因此虽然 memcmp()
可以正常工作,但由于未对齐访问,直接比较会触发 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
,所以这不是问题,但对于编译器优化而言,再一次将其视为理所当然的错误形式。
回答我自己的问题,因为 Eugene 没有 post 官方回答:
来自 gcc ARM 选项:
By default unaligned access is disabled for all pre-ARMv6, all ARMv6-M
and for ARMv8-M Baseline architectures, and enabled for all other
architectures.
这意味着 ARMv7-M 默认允许 未对齐访问。事实证明这是有道理的,因为来自 ARMv7-M Architecture Reference Manual:
The following data accesses support unaligned addressing, and only
generate alignment faults when the CCR.UNALIGN_TRP bit is set to 1,
see Configuration and Control Register:
• Non halfword-aligned LDR{S}H{T} and STRH{T}.
• Non halfword-aligned TBH.
• Non word-aligned LDR{T} and STR{T}.
这意味着 ARMv7-M 支持一组有限的未对齐访问。 但是,它不支持所有个非对齐访问:
The following data accesses always generate an alignment fault:
• Non halfword-aligned LDREXH and STREXH.
• Non word-aligned LDREX and STREX.
• Non word-aligned LDRD, LDMIA, LDMDB, POP, LDC, VLDR, VLDM, and VPOP.
• Non word-aligned STRD, STMIA, STMDB, PUSH, STC, VSTR, VSTM, and
VPUSH.
还有:
Accesses to Strongly Ordered and Device memory types must always be
naturally aligned
所以这是促使我提出最初问题的失败情况:
- 启用优化的 gcc 正在用直接比较替换 4 字节
memcmp()
,默认情况下 是 允许的,因为默认情况下允许未对齐的访问。所以这不是编译器错误。
- 包含
memcmp()
数据的闪存区域位于声明 Strongly Ordered
的 MPU 段中, 不支持 未对齐的访问。因此,当 memcmp()
被直接比较替换,并且数据落在未对齐的地址上时,比较会触发 HardFault
.
Eugene 在他最初的评论中得到正确的修复是将 -mno-unaligned-access
添加到编译器选项。在我的例子中,这仍然允许编译器用直接 4 字节比较替换 memcmp()
,但它也强制数据对齐 4 字节,允许比较成功而不会触发错误条件。
运行 Atmel Studio 及其提供的 gcc 6.3.1 为 Atmel/Microchip SAMV70 (ARM Cortex-M7) 芯片构建固件。我有使用 memcmp()
将 4 字节输入数组与 4 字节本地数组进行比较的代码。当使用 -O0
编译以禁用优化时,它工作正常。当使用 -Os
编译以优化大小或使用 -O3
进行最大优化时,编译器将 memcmp()
调用替换为直接 4 字节比较(通过检查反汇编进行验证)。不幸的是,优化有时也会将本地 4 字节数组移动到未对齐的起始地址,因此虽然 memcmp()
可以正常工作,但由于未对齐访问,直接比较会触发 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
,所以这不是问题,但对于编译器优化而言,再一次将其视为理所当然的错误形式。
回答我自己的问题,因为 Eugene 没有 post 官方回答:
来自 gcc ARM 选项:
By default unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures.
这意味着 ARMv7-M 默认允许 未对齐访问。事实证明这是有道理的,因为来自 ARMv7-M Architecture Reference Manual:
The following data accesses support unaligned addressing, and only generate alignment faults when the CCR.UNALIGN_TRP bit is set to 1, see Configuration and Control Register:
• Non halfword-aligned LDR{S}H{T} and STRH{T}.
• Non halfword-aligned TBH.
• Non word-aligned LDR{T} and STR{T}.
这意味着 ARMv7-M 支持一组有限的未对齐访问。 但是,它不支持所有个非对齐访问:
The following data accesses always generate an alignment fault:
• Non halfword-aligned LDREXH and STREXH.
• Non word-aligned LDREX and STREX.
• Non word-aligned LDRD, LDMIA, LDMDB, POP, LDC, VLDR, VLDM, and VPOP.
• Non word-aligned STRD, STMIA, STMDB, PUSH, STC, VSTR, VSTM, and VPUSH.
还有:
Accesses to Strongly Ordered and Device memory types must always be naturally aligned
所以这是促使我提出最初问题的失败情况:
- 启用优化的 gcc 正在用直接比较替换 4 字节
memcmp()
,默认情况下 是 允许的,因为默认情况下允许未对齐的访问。所以这不是编译器错误。 - 包含
memcmp()
数据的闪存区域位于声明Strongly Ordered
的 MPU 段中, 不支持 未对齐的访问。因此,当memcmp()
被直接比较替换,并且数据落在未对齐的地址上时,比较会触发HardFault
.
Eugene 在他最初的评论中得到正确的修复是将 -mno-unaligned-access
添加到编译器选项。在我的例子中,这仍然允许编译器用直接 4 字节比较替换 memcmp()
,但它也强制数据对齐 4 字节,允许比较成功而不会触发错误条件。