Reputation:
I'm developing some software for a STM32F4 controller (Cortex M4). The other day I was porting my code to a new HW platform, hereby creating a new project in the "System Workbench for STM32" IDE.
When I tried to run the new project, I found memcpy() causing an UsageFault, caused by 32bit-wide Load/Store accessing an uneven address.
I then found out that the old working code had been linked with "-specs=nano" whereas the crashing code was not, so the problem could be fixed easily. I checked the disassembly of memcpy() and found that the Nano library in fact has a very different implementation than the standard (?) libc.
Nevertheless, I'm confused! Why would an implementation of memcpy() not support byte-aligned addresses? That would be a rather trivial bug. There has to be more it?! Anybody knows?
Upvotes: 0
Views: 1659
Reputation: 7691
When I tried to run the new project, I found memcpy() causing an UsageFault, caused by 32bit-wide Load/Store accessing an uneven address.
Are you sure it was a 32-bit access and not a 64-bit one (LDRD/STRD instruction)? The former should not crash on a Cortex-M4 at all, unless the MCU is explicitly set up to do so.
All Armv7-M (that includes every Cortex-M but Cortex-M0) support LDR and STR instructions with odd memory addresses. Only the 64-bit variants LDRD/STRD crash on misalignment by default.
Unfortunately FPU loads and stores also crash on -M4F when misaligned. This got me a few times when porting old 8-bit stuff.
Why would an implementation of memcpy() not support byte-aligned addresses?
Modern GCC can use build-ins for memcpy()
, especially whith fixed transfer sizes and Pointers to larger types than one byte (say uint32_t*
or float*
). Nano memcpy()
is a minimal implementation that copies slowly byte-for-byte.
You could also try to cast the pointers back to a byte sized type:
uint32_t *pa,*pb;
memcpy((uint8_t*)pa,(uint8_t*)pb, MEMCPY_SIZE);
That should hint the compiler to not use alignmnent sensitive build-ins.
Upvotes: 1