我有一个对象的地址不是 4 字节对齐的。当存在保存 2 个寄存器的 STR 指令时,这会导致 cpu 出现 HardFault 错误。
这是生成的代码:
00000000 <_ZN8BaseAreaC1EPcmm>:
0: b510 push {r4, lr}
2: 4604 mov r4, r0
4: 6042 str r2, [r0, #4]
6: e9c4 3102 strd r3, r1, [r4, #8]
a: 2001 movs r0, #1
c: 7420 strb r0, [r4, #16]
e: b921 cbnz r1, 1a <_ZN8BaseAreaC1EPcmm+0x1a>
这些是在“4: 6042...”行时的寄存器
R0 08738B82 R8 0
R1 08738BAE R9 0
R2 0 R10 082723E0
R3 2FCC R11 0
R4 08738B82 R12 0
R5 20007630 R13 2000CB38
正如所见,STR 指令的目标寄存器未按 4 字节对齐。指令 STR r2, [r0, #4]
执行良好。但它会在下一个 STRD r3, r1, [r4, #8]
上发生硬故障。如果我手动将寄存器 R4 更改为 08738B80
,它不会出现硬故障。
这是生成上述 asm 的 C++ 代码:
BaseArea::BaseArea(char * const pAddress, unsigned long startOffset, unsigned long endOffset) :
m_pAddress(pAddress), m_start(startOffset), m_end(endOffset), m_eAreaType(BASE_AREA) {
而m_start
是类中的第一个变量,与this
具有相同的地址(0x08738B82
),m_end
在 0x08738B86
之后。
如何让对象按 4 字节对齐? 有人对此有其他解决方案吗?
最佳答案
在基于 ARM 的系统上,您经常无法寻址未与 4 字节边界对齐的 32 位字(正如您的错误告诉您的那样)。在 x86 上,您可以访问非对齐数据,但是这会对性能造成巨大影响。如果 ARM 部件确实支持未对齐访问(例如单字正常加载),则性能会下降并且应该有一个可配置的异常陷阱。
ARM ( here ) 上的边界错误示例,TLDR:存储指向 unsigned char
的指针,然后尝试将其转换为 double *
(double指针)。
要解决您的问题,您需要请求一个 4 字节对齐的内存块并复制未对齐的字节 + 用垃圾字节填充它以确保它是 4 字节对齐的(因此执行数据结构对齐手动)。然后,您可以将该对象解释为与其新地址对齐的 4 字节。
来自 TurboJ 的评论,显式错误:
Cortex-M3 and M4 allow unaligned access by default. But they do not allow unalinged access with the STRD instruction, hence the fault.
您可能还会发现查看 this 很有帮助用于强制 ARM 上的数据结构对齐。
关于c++ - 未对齐访问导致 ARM Cortex-M4 出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18269181/