简体   繁体   English

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

[英]Unaligned access causes error on ARM Cortex-M4

I have an object that has an address that is not 4-byte aligned.我有一个 object,它的地址不是 4 字节对齐的。 This causes a HardFault error in the cpu when there is a STR instruction saving 2 registers.当存在保存 2 个寄存器的 STR 指令时,这会导致 cpu 出现 HardFault 错误。

This is the generated code:这是生成的代码:

   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>

These are the registers when at line "4: 6042..."这些是在“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  

As seen the target register for STR-instructions are not aligned on 4-byte.如所见,STR 指令的目标寄存器未按 4 字节对齐。 The instruction STR r2, [r0, #4] is executed fine.指令STR r2, [r0, #4]执行良好。 But it HardFaults on the next STRD r3, r1, [r4, #8] .但它会在下一个STRD r3, r1, [r4, #8]上发生硬故障。 If I manually change register R4 to 08738B80 it does not hardfault.如果我手动将寄存器 R4 更改为08738B80 ,它不会出现硬故障。

This is the C++ code that generates the above asm:这是生成上述 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) {

And m_start is the first variable in the class and has the same address as this ( 0x08738B82 ), m_end follows after on 0x08738B86 . m_start是 class 中的第一个变量,与this具有相同的地址( 0x08738B82 ), m_end0x08738B86之后。

How do I get the object aligned on 4-byte?如何使 object 在 4 字节上对齐? Anyone have some other solution to this?有人对此有其他解决方案吗?

On ARM-based systems you frequently cannot address a 32-bit word that is not aligned to a 4-byte boundary (as your error is telling you). 在基于ARM的系统上,您经常无法处理未与4字节边界对齐的32位字(正如您的错误告诉您的那样)。 On x86 you can access non-aligned data, however there is a huge hit on performance. 在x86上,您可以访问非对齐数据,但性能会受到很大影响。 Where an ARM part does support unaligned accesses (eg single word normal load), there is a performance penalty and there should be a configurable exception trap. 如果ARM部件支持未对齐访问(例如,单字正常负载),则存在性能损失, 并且应该存在可配置的异常陷阱。

Example of boundary error on ARM ( here ), TLDR: storing a pointer to an unsigned char and then attempting to convert it to a double * (double pointer). ARM上的边界错误示例( 此处 ),TLDR:存储指向unsigned char的指针,然后尝试将其转换为double * (双指针)。

To solve your problem, you would need to request a block of memory that is 4-byte aligned and copy the non-aligned bytes + fill it with garbage bytes to ensure it is 4 byte-aligned (hence perform data structure alignment manually). 要解决您的问题,您需要请求一个4字节对齐的内存块并复制非对齐字节+用垃圾字节填充它以确保它是4字节对齐的(因此手动执行数据结构对齐)。 Then, you can interpret that object as 4-byte aligned from its new address. 然后,您可以将该对象从其新地址解释为4字节对齐。

From TurboJ in comments, the explicit error: 来自TurboJ的评论中,显式错误:

Cortex-M3 and M4 allow unaligned access by default. 默认情况下,Cortex-M3和M4允许未对齐访问。 But they do not allow unalinged access with the STRD instruction, hence the fault. 但是他们不允许使用STRD指令进行无法访问,因此就是错误。

You may also find it helpful to look into this for forcing data structure alignment on ARM. 你也可以发现它有助于看看对ARM迫使数据结构对齐。

Following is true for ARM architecture at least (verified on cortex M0): 以下情况至少适用于ARM体系结构(在cortex M0上验证):

When using load and store instructions, the memory that we access must be divisible by the number of bytes we are trying to access from/to the memory, or we will get an hard fault exception. 使用加载和存储指令时,我们访问的内存必须能够被我们尝试从内存访问/到内存的字节数整除,否则我们将获得硬故障异常。

eg: 例如:

LDR r0, = 0x1001
LDR r1, [r0]

The second line in the above code will give hard fault since are trying to read 4 bytes but the memory address is not divisible by 4 上面代码中的第二行将给出硬错误,因为它试图读取4个字节,但内存地址不能被4整除

If we change the second line in above code to the following 如果我们将上面代码中的第二行更改为以下内容

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

The above line will not produce a hard fault, since we are trying to access 1 byte(1 byte can be accessed from any memory location) 上面的行不会产生硬故障,因为我们试图访问1个字节(可以从任何内存位置访问1个字节)

Also notice the following example; 另请注意以下示例;

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

The above line will not produce a hard fault, since the memory access is 2 bytes and the address is divisible by 2. 上述行不会产生硬故障,因为内存访问是2个字节,地址可以被2整除。

As you've discovered, Cortex-M4 supports 4-byte unaligned access but not 8-byte unaligned access.正如您所发现的,Cortex-M4 支持 4 字节未对齐访问,但不支持 8 字节未对齐访问。 The latter is explained in the documentation of the UFSR.UNALIGNED bit :后者在 UFSR.UNALIGNED 位的文档中有解释:

UNALIGNED - Indicates an unaligned access operation occurred. UNALIGNED - 表示发生了未对齐的访问操作。 Unaligned multiple word accesses, such as accessing a uint64_t that is not 8-byte aligned, will always generate this fault.未对齐的多字访问,例如访问非 8 字节对齐的uint64_t ,将始终生成此错误。 With the exception of Cortex-M0 MCUs, whether or not unaligned accesses below 4 bytes generate a fault is also configurable.除了 Cortex-M0 MCU 之外,4 字节以下的未对齐访问是否产生故障也是可配置的。

The 8-byte access can be a STR instruction (as in your example) or simply accessing a uint64_t . 8 字节访问可以是 STR 指令(如您的示例所示)或只是访问uint64_t

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM