首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未对齐的访问在ARM Cortex-M4上导致错误

未对齐的访问在ARM Cortex-M4上导致错误
EN

Stack Overflow用户
提问于 2013-08-16 16:39:16
回答 2查看 12.7K关注 0票数 9

我有一个对象,其地址不是4字节对齐的。当存在保存2个寄存器的STR指令时,这会在中央处理器中导致HardFault错误。

以下是生成的代码:

代码语言:javascript
复制
   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...“行的寄存器。

代码语言:javascript
复制
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]上HardFaults。如果我手动将寄存器R4更改为08738B80,它不会硬错误。

这是生成上述asm的C++代码:

代码语言:javascript
复制
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字节上对齐?有人有其他的解决方案吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-16 16:53:55

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

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

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

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

默认情况下,

Cortex-M3和M4允许非对齐访问。但它们不允许使用STRD指令进行无限制访问,因此出现了错误。

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

票数 18
EN

Stack Overflow用户

发布于 2014-08-26 10:54:27

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

当使用load和store指令时,我们访问的内存必须能被我们试图访问的字节数整除,否则我们会得到一个硬故障异常。

例如:

代码语言:javascript
复制
LDR r0, = 0x1001
LDR r1, [r0]

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

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

LDRB r1, [r0];//从地址加载1个字节

上面这行代码不会产生硬错误,因为我们正在尝试访问1个字节(可以从任何内存位置访问1个字节)

另请注意下面的示例;

代码语言:javascript
复制
LDR r0,= 0x1002
LDRH r1,[r0];   //Load half word from 0x1002

由于存储器访问是2字节,并且地址可以被2整除,因此上面的行不会产生硬故障。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18269181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档