未对齐访问会导致ARM Cortex-M4出错

rdr*_*ntn 8 c c++ arm memory-alignment cortex-m

我有一个对象,其地址不是4字节对齐的.当存在STR指令保存2个寄存器时,这会在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>
Run Code Online (Sandbox Code Playgroud)

这些是在"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  
Run Code Online (Sandbox Code Playgroud)

如图所示,STR指令的目标寄存器未在4字节上对齐.该指令STR r2, [r0, #4]执行正常.但它就是HardFaults的下一个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) {
Run Code Online (Sandbox Code Playgroud)

并且m_start是类中的第一个变量,并且具有相同的地址this (08738B82),m_end在继续之后0x08738B86.

如何在4字节上对齐对象?任何人都有其他解决方案吗?

Jac*_*ack 16

在基于ARM的系统上,您无法处理未与4字节边界对齐的32位字(正如您的错误告诉您的那样).在x86上,您可以访问非对齐数据,但性能会受到很大影响.

ARM上的边界错误示例(此处),TLDR:存储指向a的指针unsigned char,然后尝试将其转换为double *(双指针).

要解决您的问题,您需要请求一个4字节对齐的内存块并复制非对齐字节+用垃圾字节填充它以确保它是4字节对齐的(因此手动执行数据结构对齐).然后,您可以将该对象从其新地址解释为4字节对齐.

来自TurboJ的评论中,显式错误:

默认情况下,Cortex-M3和M4允许未对齐访问.但是他们不允许使用STRD指令进行无法访问,因此就是错误.

你也可以发现它有助于看看对ARM迫使数据结构对齐.

  • 默认情况下,Cortex-M3和M4允许未对齐访问.但他们确实*不允许使用`STRD`指令进行无法访问,因此就是错误. (3认同)