C++ 未对齐的访问导致ARM Cortex-M4出错

C++ 未对齐的访问导致ARM Cortex-M4出错,c++,c,arm,memory-alignment,cortex-m,C++,C,Arm,Memory Alignment,Cortex M,我有一个对象的地址不是4字节对齐的。当存在保存2个寄存器的STR指令时,这会在cpu中导致硬故障错误 这是生成的代码: 00000000 <_ZN8BaseAreaC1EPcmm>: 0: b510 push {r4, lr} 2: 4604 mov r4, r0 4: 6042 str r2, [r0, #4] 6: e9c4 3102

我有一个对象的地址不是4字节对齐的。当存在保存2个寄存器的STR指令时,这会在cpu中导致硬故障错误

这是生成的代码:

   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>
如图所示,STR指令的目标寄存器未按4字节对齐。指令STR r2、[r0、#4]执行良好。但它在下一个
标准r3,r1,[r4,#8]
上硬故障。如果我手动将寄存器R4更改为
08738B80
,则不会出现硬故障

这是生成上面ASM:< /P>的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
是类中的第一个变量,与
此(08738B82)
具有相同的地址,m_end紧跟在
0x08738B86
之后

如何使对象按4字节对齐?
有人有其他解决方案吗?

在基于ARM的系统上,您经常无法处理与4字节边界不对齐的32位字(错误告诉您)。在x86上,您可以访问不一致的数据,但这会对性能造成巨大影响。如果ARM部件不支持未对齐的访问(例如,单字正常加载),则会造成性能损失,并且应该有一个可配置的异常陷阱

ARM()、TLDR上的边界错误示例:存储指向
无符号字符的指针,然后尝试将其转换为
双*
(双指针)

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

从注释中的TurboJ中,显式错误:


默认情况下,Cortex-M3和M4允许未对齐的访问。但它们不允许使用STRD指令进行无延迟访问,因此存在故障


您可能还发现,研究如何在ARM上强制数据结构对齐很有帮助。

以下内容至少适用于ARM体系结构(在cortex M0上验证):

当使用load和store指令时,我们访问的内存必须可以被我们试图从内存访问/访问内存的字节数整除,否则我们将得到硬故障异常

例如:

上面代码中的第二行将给出硬错误,因为您试图读取4个字节,但内存地址不能被4整除

如果我们将上面代码中的第二行更改为

ldrbr1[r0]//从地址加载1字节

上述行不会产生硬故障,因为我们试图访问1个字节(1个字节可以从任何内存位置访问)

还要注意下面的例子

LDR r0,= 0x1002
LDRH r1,[r0];   //Load half word from 0x1002

上述行不会产生硬故障,因为内存访问是2字节,地址是2可除的。

您是否在汇编程序中编程,或者是由C编译器生成的代码?@ JoaCHIMPILBORG:因为它有明确的“被损坏的C++名字”,我怀疑这是C++代码。这是C++生成的汇编代码。@ JOTAN:什么是<代码>类< /代码>或<代码>结构> /代码>您在这里使用。(在
r0
中的值可能是我们正在处理的对象的
this
。换句话说,是什么源代码生成的?如果您告诉我们您在x86上使用的编译器(例如gcc、armcc等),也可能会有所帮助。只有当您的访问跨越64B行边界时,性能才会受到影响(或者——但愿不会——页面边界)。仅仅访问一行中几个未对齐的字节并不重要,您只需缓存整行即可。@Leeor,我将我的初始答案作为社区wiki,因为ARM不是我太熟悉的领域(让其他人参与一个集体的、强有力的答案)。有很多细节我确信我忽略了或没有说明,请随意分别编辑原始帖子。对不起,我可能对ARM微体系结构更不熟悉,我说的是x86参考Hanks!问题是,未对齐的地址源自包括sizeof()在内的大量计算地址已对齐为2字节。我将修改代码的该部分,使其对齐为4字节。默认情况下,Cortex-M3和M4允许未对齐的访问。但它们不允许使用
STRD
指令进行未对齐的访问,因此出现了故障。对于Cortex-M3,至少具有LDR和STR指令的非字对齐地址支持未对齐的访问仅当配置控制寄存器中的UNALIGN_TRP位为“1”时,才能访问并生成对齐故障。
LDR r0, = 0x1001
LDR r1, [r0]
LDR r0,= 0x1002
LDRH r1,[r0];   //Load half word from 0x1002