This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ARM GCC - Some call to memcpy results in exception

I've been using the ARM GCC release aarch64-none-elf-gcc-11.2.1 in a baremetal project for some time in a large project that has successfully used libc functions (malloc/memcpy) many times without issue using these options -L

Fullscreen
1
$AARCH64_GCC_PATH/aarch64-none-elf/lib -lc -lnosys -lg
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
.

I recently saw an exception due to an unaligned access during memcpy despite compiling with -mstrict-align.

After isolating the issue and creating a unit test I believe I've found a bug, please ignore the addresses from the objdump and memcpy call, just made them up for this test.

When performing a memcpy on device type memory where size = 0x8 + 0x4*n where n is any natural number.

An exception will be thrown as even though care may be taken to have src/dst pointers aligned, the instruction seen on 6009c from the below objdump of memcpy on aarch64 leads to ldur    x7, [x4, #-8]. Which in the case of a size 0xc copy would do an LDUR of a 32bit aligned address ending in 0x4 to a 64 bit x* register, which results in a Data Abort.

Fullscreen
1
2
3
4
5
6
7
8
//unit test
#include <stdlib.h>
#include <string.h>
volatile int bssTest;
void swap(int a, int b) {
memcpy((void*)0x500,(void*)0x1000,0xc);
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0000000000060040 <memcpy>:
60040: f9800020 prfm pldl1keep, [x1]
60044: 8b020024 add x4, x1, x2
60048: 8b020005 add x5, x0, x2
6004c: f100405f cmp x2, #0x10
60050: 54000209 b.ls 60090 <memcpy+0x50> // b.plast
60054: f101805f cmp x2, #0x60
60058: 54000648 b.hi 60120 <memcpy+0xe0> // b.pmore
6005c: d1000449 sub x9, x2, #0x1
60060: a9401c26 ldp x6, x7, [x1]
60064: 37300469 tbnz w9, #6, 600f0 <memcpy+0xb0>
60068: a97f348c ldp x12, x13, [x4, #-16]
6006c: 362800a9 tbz w9, #5, 60080 <memcpy+0x40>
60070: a9412428 ldp x8, x9, [x1, #16]
60074: a97e2c8a ldp x10, x11, [x4, #-32]
60078: a9012408 stp x8, x9, [x0, #16]
6007c: a93e2caa stp x10, x11, [x5, #-32]
60080: a9001c06 stp x6, x7, [x0]
60084: a93f34ac stp x12, x13, [x5, #-16]
60088: d65f03c0 ret
6008c: d503201f nop
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

While I understand that care must be taken when using stdlib functions in a baremetal application, due to the nature of our codebase it would be very difficult to ensure that every call to memcpy has a size that is 64bit aligned. Shouldn't newlib/compiler take care to ensure that memcpy will use 32bit w registers for any 32bit aligned memcpy anyway? Especially with -mstrict-align?

What are my options as far as providing an immediate fix in the meantime, I suppose I could try to override the definition of memcpy but what source should I base the replacement implementation on in that case.

Any help on this is appreciated, thanks.

0