我正在开发一个带有GCC的嵌入式系统,并且只想使用libc中的一些符号。例如,我想使用基本的memcpy,memmove,memset,strlen,strcpy等。但是,我想提供我自己的(较小的)printf函数,所以我不希望libc私有printf。我不想在这个平台上进行动态分配,所以我不想让malloc完全解决。
有没有办法告诉GCC“只提供这些符号”来自libc?
编辑:要清楚,我问是否有一种方法我只能从库中提供一些特定符号,而不仅仅是用我自己的实现覆盖库函数。如果代码使用库中但未指定的符号,则链接器将失败并显示“未解析的符号”。如果另一个问题解释了如何做到这一点,我还没有看到它。
答案 0 :(得分:2)
只要您的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
没有(不能)链接和使用。
答案 1 :(得分:-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
相关联。这使您可以最好地控制从哪个源使用哪些符号。