2016-02-28 84 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