我正在使用带有裸机工具链的皮质m3板,没有libc。
我实现了memcpy,它会逐字节地复制数据,但速度太慢。在GCC手册中,它说它提供了__builtin_memcpy,我决定使用它。所以这是使用__builtin_memcpy的实现。
#include <stddef.h>
void *memcpy(void *dest, const void *src, size_t n)
{
return __builtin_memcpy(dest,src,n);
}
当我编译这段代码时,它变成了一个永远不会结束的递归函数。
$ arm-none-eabi-gcc -march=armv7-m -mcpu=cortex-m3 -mtune=cortex-m3 \
-O2 -ffreestanding -c memcpy.c -o memcpy.o
$ arm-none-eabi-objdump -d memcpy.o
memcpy.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <memcpy>:
0: f7ff bffe b.w 0 <memcpy>
我做错了吗?如何使用编译器生成的memcpy版本?
答案 0 :(得分:4)
内置函数不应该用于实现自己:)
应该在应用程序代码中使用内置函数 - 然后编译器可能生成或不生成一些特殊 insn序列或对底层实函数的调用
比较
int a [10], b [20];
void
foo ()
{
__builtin_memcpy (a, b, 10 * sizeof (int));
}
这导致:
foo:
stmfd sp!, {r4, r5}
ldr r4, .L2
ldr r5, .L2+4
ldmia r4!, {r0, r1, r2, r3}
mov ip, r5
stmia ip!, {r0, r1, r2, r3}
ldmia r4!, {r0, r1, r2, r3}
stmia ip!, {r0, r1, r2, r3}
ldmia r4, {r0, r1}
stmia ip, {r0, r1}
ldmfd sp!, {r4, r5}
bx lr
可是:
void
bar (int n)
{
__builtin_memcpy (a, b, n * sizeof (int));
}
导致调用memcpy函数:
bar:
mov r2, r0, asl #2
stmfd sp!, {r3, lr}
ldr r1, .L5
ldr r0, .L5+4
bl memcpy
ldmfd sp!, {r3, lr}
bx lr
答案 1 :(得分:1)
理论上,库不是C编译器的一部分,也不是工具链的一部分。
因此,如果您编写memcpy(&a,&b,sizeof(a))
编译器必须生成子例程调用。
__builtin的想法:告知编译器,该函数是标准的并且可以进行优化。因此,如果您编写__builtin_memcpy(&a,&b,sizeof(a))
编译器可以生成子例程调用,但在大多数情况下它不会发生。例如,如果在编译时将size称为4,则只会生成一个mov
命令。 (另一个优点 - 即使在子程序调用编译器被通知的情况下,该库函数也没有副作用)。
因此,使用__builtin_memcpy而不是memcpy总是更好。在现代图书馆中,它仅由#define memcpy __builtin_memcpy
在string.h中完成
但是你仍然需要在某处实现memcpy,调用将在诡辩的地方生成。对于ARM上的字符串函数,严格建议使用4字节实现。