如何强制 arm gcc 编译器不对未对齐的内存使用 32 位访问
how to force arm gcc compiler to not to use 32bit access for an unaligned memory
我正在处理无法处理未对齐地址上的 32 位访问的内存。对于未对齐的地址,内存支持 8 位级别的访问。
在我的代码中有一个 memcpy,当我将一个未对齐的地址传递给 memcpy 时,芯片卡住了。
深入了解后,我发现生成的 memcpy 汇编代码正在对地址进行 32 位访问,而不管给定地址是否与 32 位对齐。当我将优化级别降低到 O(2) 时,编译器会生成始终执行 8 位访问的代码。
[编辑]:下面是我正在使用的 memcpy 代码
void* memcpy(void * restrict s1, const void * restrict s2, size_t n)
{
char* ll = (char*)s1;
char* rr = (char*)s2;
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
return s1;
}
下面是代码的反汇编
void* memcpy3(void *s1, void *s2, size_t n)
{
char* ll = (char*)s1;
char* rr = (char*)s2;
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
0: b38a cbz r2, 66 <memcpy3+0x66>
{
2: b4f0 push {r4, r5, r6, r7}
4: 1d03 adds r3, r0, #4
6: 1d0c adds r4, r1, #4
8: 42a0 cmp r0, r4
a: bf38 it cc
c: 4299 cmpcc r1, r3
e: d31e bcc.n 4e <memcpy3+0x4e>
10: 2a08 cmp r2, #8
12: d91c bls.n 4e <memcpy3+0x4e>
14: 460d mov r5, r1
16: 4604 mov r4, r0
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
18: 2300 movs r3, #0
1a: 0897 lsrs r7, r2, #2
1c: f855 6b04 ldr.w r6, [r5], #4
20: 3301 adds r3, #1
22: 429f cmp r7, r3
24: f844 6b04 str.w r6, [r4], #4
28: d8f8 bhi.n 1c <memcpy3+0x1c>
2a: f022 0303 bic.w r3, r2, #3
2e: 429a cmp r2, r3
30: d00b beq.n 4a <memcpy3+0x4a>
32: 56cd ldrsb r5, [r1, r3]
34: 1c5c adds r4, r3, #1
36: 42a2 cmp r2, r4
38: 54c5 strb r5, [r0, r3]
3a: d906 bls.n 4a <memcpy3+0x4a>
3c: 570d ldrsb r5, [r1, r4]
3e: 3302 adds r3, #2
40: 429a cmp r2, r3
42: 5505 strb r5, [r0, r4]
44: d901 bls.n 4a <memcpy3+0x4a>
46: 56ca ldrsb r2, [r1, r3]
48: 54c2 strb r2, [r0, r3]
return s1;
}
4a: bcf0 pop {r4, r5, r6, r7}
4c: 4770 bx lr
4e: 3a01 subs r2, #1
50: 440a add r2, r1
52: 1e43 subs r3, r0, #1
54: 3901 subs r1, #1
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
56: f911 4f01 ldrsb.w r4, [r1, #1]!
5a: 4291 cmp r1, r2
5c: f803 4f01 strb.w r4, [r3, #1]!
60: d1f9 bne.n 56 <memcpy3+0x56>
}
62: bcf0 pop {r4, r5, r6, r7}
64: 4770 bx lr
66: 4770 bx lr
是否可以将 arm-gcc 编译器配置为不对未对齐的地址使用 32 位访问。
使用-mno-unaligned-access
标志告诉编译器不要使用未对齐访问。默认情况下,编译器使用 -munaligned-access
.
使用“-mcpu=”标志设置处理器类型,而不是“-march=”,因为它涵盖了更多选项。
处理器确定是否允许对总线接口进行未对齐访问。但是在访问内存设备之前,未对齐的访问将被翻译成更小的部分。说内存不支持未对齐访问确实没有意义,因为无论内核做什么,它都看不到它们。
我正在处理无法处理未对齐地址上的 32 位访问的内存。对于未对齐的地址,内存支持 8 位级别的访问。
在我的代码中有一个 memcpy,当我将一个未对齐的地址传递给 memcpy 时,芯片卡住了。 深入了解后,我发现生成的 memcpy 汇编代码正在对地址进行 32 位访问,而不管给定地址是否与 32 位对齐。当我将优化级别降低到 O(2) 时,编译器会生成始终执行 8 位访问的代码。
[编辑]:下面是我正在使用的 memcpy 代码
void* memcpy(void * restrict s1, const void * restrict s2, size_t n)
{
char* ll = (char*)s1;
char* rr = (char*)s2;
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
return s1;
}
下面是代码的反汇编
void* memcpy3(void *s1, void *s2, size_t n)
{
char* ll = (char*)s1;
char* rr = (char*)s2;
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
0: b38a cbz r2, 66 <memcpy3+0x66>
{
2: b4f0 push {r4, r5, r6, r7}
4: 1d03 adds r3, r0, #4
6: 1d0c adds r4, r1, #4
8: 42a0 cmp r0, r4
a: bf38 it cc
c: 4299 cmpcc r1, r3
e: d31e bcc.n 4e <memcpy3+0x4e>
10: 2a08 cmp r2, #8
12: d91c bls.n 4e <memcpy3+0x4e>
14: 460d mov r5, r1
16: 4604 mov r4, r0
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
18: 2300 movs r3, #0
1a: 0897 lsrs r7, r2, #2
1c: f855 6b04 ldr.w r6, [r5], #4
20: 3301 adds r3, #1
22: 429f cmp r7, r3
24: f844 6b04 str.w r6, [r4], #4
28: d8f8 bhi.n 1c <memcpy3+0x1c>
2a: f022 0303 bic.w r3, r2, #3
2e: 429a cmp r2, r3
30: d00b beq.n 4a <memcpy3+0x4a>
32: 56cd ldrsb r5, [r1, r3]
34: 1c5c adds r4, r3, #1
36: 42a2 cmp r2, r4
38: 54c5 strb r5, [r0, r3]
3a: d906 bls.n 4a <memcpy3+0x4a>
3c: 570d ldrsb r5, [r1, r4]
3e: 3302 adds r3, #2
40: 429a cmp r2, r3
42: 5505 strb r5, [r0, r4]
44: d901 bls.n 4a <memcpy3+0x4a>
46: 56ca ldrsb r2, [r1, r3]
48: 54c2 strb r2, [r0, r3]
return s1;
}
4a: bcf0 pop {r4, r5, r6, r7}
4c: 4770 bx lr
4e: 3a01 subs r2, #1
50: 440a add r2, r1
52: 1e43 subs r3, r0, #1
54: 3901 subs r1, #1
for (size_t i = 0; i < n; i++) ll[i] = rr[i];
56: f911 4f01 ldrsb.w r4, [r1, #1]!
5a: 4291 cmp r1, r2
5c: f803 4f01 strb.w r4, [r3, #1]!
60: d1f9 bne.n 56 <memcpy3+0x56>
}
62: bcf0 pop {r4, r5, r6, r7}
64: 4770 bx lr
66: 4770 bx lr
是否可以将 arm-gcc 编译器配置为不对未对齐的地址使用 32 位访问。
使用-mno-unaligned-access
标志告诉编译器不要使用未对齐访问。默认情况下,编译器使用 -munaligned-access
.
使用“-mcpu=”标志设置处理器类型,而不是“-march=”,因为它涵盖了更多选项。
处理器确定是否允许对总线接口进行未对齐访问。但是在访问内存设备之前,未对齐的访问将被翻译成更小的部分。说内存不支持未对齐访问确实没有意义,因为无论内核做什么,它都看不到它们。