Использование встроенных функций GCC в руке - PullRequest
4 голосов
/ 14 декабря 2011

Я работаю на плате cortex-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?

Ответы [ 2 ]

4 голосов
/ 14 декабря 2011

Встроенные функции не должны использоваться для самореализации:)

Встроенные функции должны использоваться в коде приложения - тогда компилятор может генерировать или не генерировать некоторые специальные 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 голос
/ 07 августа 2014

Теоретически, библиотека не является частью компилятора C и не является частью toolchain. Таким образом, если вы написали memcpy(&a,&b,sizeof(a)), компилятор ДОЛЖЕН сгенерировать вызов подпрограммы.

Идея __builtin: сообщить компилятору, что функция стандартна и может быть оптимизирована. Таким образом, если вы написали __builtin_memcpy(&a,&b,sizeof(a)), компилятор МОЖЕТ генерировать вызов подпрограммы, но в большинстве случаев этого не произойдет. Например, если размер известен как 4 во время компиляции - будет сгенерирована только одна команда mov. (Еще одно преимущество - даже в том случае, если компилятор вызова подпрограммы информируется, что библиотечная функция не имеет побочных эффектов).

Итак, ВСЕГДА лучше использовать __builtin_memcpy вместо memcpy. В современных библиотеках это было сделано #define memcpy __builtin_memcpy только в string.h

Но вам все равно нужно где-нибудь реализовать memcpy, вызов будет сгенерирован в сложных местах. Для строковых функций в ARM строго рекомендуется 4-байтовая реализация.

...