仅链接库

时间:2016-02-28 20:08:23

标签: c gcc embedded ld libc

我正在开发一个带有GCC的嵌入式系统,并且只想使用libc中的一些符号。例如,我想使用基本的memcpy,memmove,memset,strlen,strcpy等。但是,我想提供我自己的(较小的)printf函数,所以我不希望libc私有printf。我不想在这个平台上进行动态分配,所以我不想让malloc完全解决。

有没有办法告诉GCC“只提供这些符号”来自libc?

编辑:要清楚,我问是否有一种方法我只能从库中提供一些特定符号,而不仅仅是用我自己的实现覆盖库函数。如果代码使用库中但未指定的符号,则链接器将失败并显示“未解析的符号”。如果另一个问题解释了如何做到这一点,我还没有看到它。

2 个答案:

答案 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相关联。这使您可以最好地控制从哪个源使用哪些符号。