Unaligned access causes error on ARM Cortex-M4

rdrmntn picture rdrmntn · Aug 16, 2013 · Viewed 11.7k times · Source

I have an object that has an address that is not 4-byte aligned. This causes a HardFault error in the cpu when there is a STR instruction saving 2 registers.

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..."

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. The instruction STR r2, [r0, #4] is executed fine. But it HardFaults on the next STRD r3, r1, [r4, #8]. If I manually change register R4 to 08738B80 it does not hardfault.

This is the C++ code that generates the above asm:

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 (08738B82), m_end follows after on 0x08738B86.

How do I get the object aligned on 4-byte? Anyone have some other solution to this?

Answer

Jacob Pollack picture Jacob Pollack · Aug 16, 2013

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). On x86 you can access non-aligned data, however there is a huge hit on performance. Where an ARM part does support unaligned accesses (e.g. single word normal load), there is a performance penalty and there should be a configurable exception trap.

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).

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). Then, you can interpret that object as 4-byte aligned from its new address.

From TurboJ in comments, the explicit error:

Cortex-M3 and M4 allow unaligned access by default. But they do not allow unalinged access with the STRD instruction, hence the fault.

You may also find it helpful to look into this for forcing data structure alignment on ARM.