2011-12-14 98 views
3

我正在使用沒有libc的裸機工具鏈的cortex-m3板。在手臂中使用GCC的內置函數

我實現了memcpy,它將byte-to-byte數據拷貝過來,但速度太慢。在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版本?不應該

回答

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

從理論上說,圖書館是不是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字節實現。

+0

兩年前問了這個問題,已經有了答案。請儘量不要帶回這些類型的問題。 – Mic1780 2014-08-06 22:57:03