GNU LD:如何替换静态库中的指定函数?
用GNU链接器解决ARM Cortex-M项目的内存分配符号冲突问题
针对你提到的三个需求,结合GNU链接器的特性,逐一解答:
1. 符号已在库外定义时,不从静态库取用该符号
这完全可以实现,而且是GNU链接器的默认行为。静态库(.a本质是一堆.o的归档文件)在链接时,只会被链接器提取那些当前还未找到定义的符号对应的目标文件。
只要你把自己实现了malloc()/free()的目标文件(比如custom_mem.o)放在链接命令中供应商库、libc.a的前面,链接器就会优先使用你定义的符号,不会再从静态库中去捞包含标准malloc/free的目标文件。
举个实际的链接命令例子:
arm-none-eabi-gcc -o app.elf your_app.o custom_mem.o -L./libs -lvendor_prebuilt -lc
这里custom_mem.o先于供应商库和libc被链接,所有对malloc/free的引用都会绑定到你自定义的实现上。
2. 排除静态库中的特定目标文件
没问题,可以做到。有两种常用方式:
- 手动重新打包静态库:先把静态库中的目标文件拆出来,去掉有问题的那个,再重新打包成新的库。比如要移除供应商库
vendor_lib.a里的bad_alloc.o:
之后链接时用# 提取所有目标文件 arm-none-eabi-ar x vendor_lib.a # 删除有问题的目标文件 rm bad_alloc.o # 重新打包成新库 arm-none-eabi-ar r new_vendor_lib.a *.onew_vendor_lib.a代替原库即可。 - 链接器选项配合:如果是要排除整个静态库的符号解析,可以用
-Wl,--exclude-libs=vendor_lib.a,但这种方式比较激进,更适合精准排除单个目标文件的场景还是手动拆包重打包更可靠。
3. 用链接脚本的PROVIDE(malloc = os_malloc)覆盖已定义的malloc符号
这点要注意:PROVIDE的作用是当符号未被任何目标文件定义时,提供一个默认实现,如果库中已经有malloc的定义,PROVIDE不会覆盖它,链接器还是会优先用已有的符号。
要强制覆盖已定义的malloc/free,推荐用更靠谱的两种方法:
--wrap链接选项:这是GNU链接器专门为符号替换设计的功能。链接时加上-Wl,--wrap=malloc,--wrap=free,链接器会自动把所有对malloc的调用替换成__wrap_malloc,原malloc会被重命名为__real_malloc;同理free对应__wrap_free和__real_free。你只需要实现__wrap_malloc和__wrap_free,内部直接调用os_malloc/os_free就行:
链接命令加上对应选项即可,这种方式灵活,还能保留原符号的调用入口(如果需要的话)。#include <stddef.h> // 声明原符号(可选,如果你不需要调用原malloc的话) void *__real_malloc(size_t size); void __real_free(void *ptr); void *__wrap_malloc(size_t size) { return os_malloc(size); } void __wrap_free(void *ptr) { os_free(ptr); }--defsym直接绑定符号:用-Wl,--defsym=malloc=os_malloc直接把malloc符号强制指向os_malloc,free同理。但这种方式要谨慎,因为如果libc中有其他函数依赖标准malloc的内部结构,可能会导致崩溃,所以优先推荐--wrap。
内容的提问来源于stack exchange,提问作者Martin Rosenau
相关产品推荐
相关产品推荐

