2016-02-28 73 views
0

我正在開發一個帶有GCC的嵌入式系統,並且只想使用libc中的幾個符號。例如,我想使用基本的memcpy,memmove,memset,strlen,strcpy等。但是,我想提供我自己的(較小的)printf函數,所以我不希望libc來提供printf函數。我不想在此平臺上進行動態分配,所以我不希望malloc根本解決。只鏈接庫中的某些符號

有沒有辦法告訴GCC「只提供這些符號」來自libc?

編輯:要清楚,我問,如果有辦法,我只能從庫中提供了幾個特定的​​符號,而不是僅僅覆蓋使用我自己的實現庫函數。如果代碼使用庫中的符號但未指定,則鏈接器將失敗並顯示「未解析的符號」。如果另一個問題解釋如何做到這一點,我還沒有看到它。

+0

[相關問題](http://stackoverflow.com/questions/29391965/what-is-partial-linking-in-gnu-linker)和[另一個相關的問題](http://stackoverflow.com/questions/270984/g-partial-linking-instead-of-archives) – Kenney

+1

[如何替換C標準庫函數?](http://stackoverflow.com/questions/9107259/how-to-replace-c-標準庫函數) –

+0

我不認爲這是重複的,因爲我的問題是「我可以告訴鏈接器只使用庫中的一部分符號」,而不是「我可以替換這個特定的函數嗎?「主要區別在於,在我的問題中,如果使用的符號未從庫中明確命名,鏈接器應該解決錯誤 – FazJaxton

回答

-1

最簡單的解決辦法可能是使用包裝定義符號和使用dlfcn在運行時解決他們:

#include <dlfcn.h> 

void* (*memcpy)(void *dest, const void *src, size_t n); 
char* (*strncpy)(char *dest, const char *src, size_t n); 
... 

void init_symbols (void) { 
    void *handle = dlopen("/lib/libc.so.6", RTLD_LAZY); 

    memcpy = dlsym(handle, "memcpy"); 
    strncpy = dlsym(handle, "strncpy"); 
    ... 
} 

-nostdlib鏈接您的二進制文件。這使您能夠從哪個來源最佳地控制使用哪些符號。

+0

這個問題被嵌入標籤,甚至可能沒有文件系統可用(OP顯然是在縮小代碼之後,這是一個明確的提示)。你如何看待動態加載庫的工作? – Olaf

1

只要您的libc和鏈接器設置支持它,這應該會「自動」發生。你還沒有告訴你的平臺是什麼,所以here is one where it does work

所以,讓我們使用snprintf創建一個愚蠢的例子。

/* 
* main.c 
*/ 
#include <stdio.h> 

int main(int argc, char **argv) { 
    char l[100]; 
    snprintf(l, 100, "%s %d\n", argv[0], argc); 
    return 0; 
} 

嘗試編譯並將其鏈接

$ CC=/opt/gcc-arm-none-eabi-4_7-2013q3/bin/arm-none-eabi-gcc 
$ CFLAGS="-mcpu=arm926ej-s -Wall -Wextra -O6" 
$ LDFLAGS="-nostartfiles -L. -Wl,--gc-sections,-emain" 
$ $CC $CFLAGS -c main.c -o main.o 
$ $CC $LDFLAGS main.o -o example 
/opt/gcc-arm-none-eabi-4_7-2013q3/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/lib/libc.a(lib_a-sbrkr.o): In function `_sbrk_r': 
sbrkr.c:(.text._sbrk_r+0x18): undefined reference to `_sbrk' 
collect2: error: ld returned 1 exit status 

它需要_sbrk因爲newlib *printf函數使用malloc這需要一種方式來分配系統內存。讓我們提供一個虛擬的。

/* 
* sbrk.c 
*/ 
#include <stdint.h> 
#include <unistd.h> 
void *_sbrk(intptr_t increment) { 
    return 0; 
} 

並編譯

$ $CC $CFLAGS -c sbrk.c -o sbrk.o 
$ $CC $LDFLAGS -Wl,-Map,"sbrk.map" main.o sbrk.o -o with-sbrk 
$ /opt/gcc-arm-none-eabi-4_7-2013q3/bin/arm-none-eabi-size with-sbrk 
    text data  bss  dec  hex filename 
    28956 2164  56 31176 79c8 with-sbrk 

嗯,這就是你想擺脫printf和朋友的原因,不是嗎?現在,隨着我們的函數替換snprintf

/* 
* replace.c 
*/ 
#include <stdio.h> 
#include <string.h> 
int snprintf(char *str, size_t size, const char *format, ...) { 
    return strlen(format); 
} 

然後編譯

$ $CC $CFLAGS -c replace.c -o replace.o 
$ $CC $LDFLAGS -Wl,-Map,"replace.map" main.o replace.o -o with-replace 
$ /opt/gcc-arm-none-eabi-4_7-2013q3/bin/arm-none-eabi-size with-sbrk 
    text data  bss  dec  hex filename 
    180  0  0  180  b4 with-replace 

請注意,我們沒有使用_sbrk存根都沒有。只要你不提供_sbrk,你可以確定malloc不是(不能)被鏈接和使用。

+0

感謝您的完整答案。 – FazJaxton