在arm中使用GCC的内置函数

4

我正在使用没有libc的裸机工具链开发cortex-m3板子。

我实现了一个逐字节复制数据的memcpy函数,但速度太慢。在GCC手册中,它提供了__builtin_memcpy,我决定使用它来改进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版本?

2个回答

5

内置函数不应该用于实现自身 :)

内置函数应该在应用程序代码中使用 - 然后编译器可能会生成一些特殊的指令序列或对底层真实函数的调用

比较:

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
理论上,库不是C编译器的一部分,也不是工具链的一部分。因此,如果您编写了memcpy(&a,&b,sizeof(a)),编译器必须生成子程序调用。
__builtin的想法是:通知编译器该函数是标准函数,可以进行优化。因此,如果您编写了__builtin_memcpy(&a,&b,sizeof(a)),编译器可能会生成子程序调用,但在大多数情况下不会发生。例如,如果大小在编译时已知为4,则仅生成一个mov命令。(另一个优点是,在进行子程序调用的情况下,编译器被告知库函数没有副作用)。
因此,始终最好使用__builtin_memcpy而不是memcpy。在现代库中,通过在string.h中使用#define memcpy __builtin_memcpy来实现。
但是,您仍然需要在某个地方实现memcpy,调用将在复杂的位置生成。对于ARM上的字符串函数,严格建议使用4字节实现。

这个问题是两年前提出的,已经有了答案。请尽量不要再提出这些类型的问题。 - Mic1780

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接