【问题标题】:Only link certain symbols from a library仅链接库中的某些符号
【发布时间】:2016-02-28 20:08:23
【问题描述】:

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

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

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

【问题讨论】:

标签: c gcc embedded ld libc


【解决方案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没有(不能)被链接和使用。

【讨论】:

  • 感谢您的完整回答。很好的猜测,我正在使用 arm-none-eabi- 和 newlib。 :)
【解决方案2】:

最简单的解决方案可能是使用一个包装器,它定义符号并在运行时使用 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 链接。这使您可以最好地控制从哪个来源使用哪些符号。

【讨论】:

  • 问题被标记为嵌入。甚至可能没有可用的文件系统(OP 显然是在缩小代码之后,这是一个明确的提示)。您如何看待动态加载库?
猜你喜欢
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-03
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多