嵌入式环境下同地址空间两项目共享依赖代码的方案问询
问题背景
我在嵌入式环境中有两个独立项目,二者依赖同一外部库,希望共享该库的代码。目前已通过链接脚本将该库的函数分离到独立段中,通过ld的-Map选项生成了第一个项目的函数地址映射,但无法让第二个项目基于此链接。
我曾考虑编写脚本解析映射文件与原库头文件,生成定义函数显式地址的头文件(示例:typedef int (*external_add_t)(int, int); external_add_t external_add = (external_add_t)(0x8dff000000);),再引入第二个项目,但希望有更优方案。
项目结构
project1/ src/project1.c project1.ldS external_lib (submodule with CMake, static dependency) CMakeLists.txt project2/ src/project2.c project2.ldS external_lib (submodule with CMake, static dependency) CMakeLists.txt external_lib/ src/external_add.c include/external_add.h
代码示例
#include "external_add.h" void project_entry_point() { // 两个项目此处逻辑不同 const uint32_t param = 1; external_add(param, 2); // 两个项目都会调用该库函数 }
编译后project1的external_add地址为0x00008d7fe0089000,project2的为0x00008d7fe0089008,期望project2复用project1生成的external_add地址。
优化方案
1. 利用链接器--just-symbols直接导入符号地址
GNU ld的--just-symbols选项可以直接从已编译的ELF文件中导入符号地址,无需手动解析映射文件:
- 完成project1的编译,得到
project1.elf - 编译project2时,在链接阶段添加该选项,同时不链接external_lib的静态库(仅保留头文件的函数声明):
链接器会自动复用project1中# 示例链接命令(以ARM嵌入式工具链为例) arm-none-eabi-ld --just-symbols=../project1/project1.elf -T project2.ldS obj/*.o -o project2.elfexternal_add的地址,无需额外脚本处理。
2. 固定链接脚本中的库段地址
如果两个项目运行在同一地址空间(如共享Flash/RAM),可以在两个项目的链接脚本中为外部库的段指定完全相同的固定地址:
- 在
project1.ldS和project2.ldS中添加相同的段定义:/* 为外部库代码段固定地址 */ .external_lib_code 0x00008d7fe0089000 : { *(.external_lib_code) /* 匹配外部库编译时指定的段属性 */ } > FLASH - 编译external_lib时,确保所有函数都被放到
.external_lib_code段(可通过编译选项-ffunction-sections配合链接脚本,或直接在代码中用__attribute__((section(".external_lib_code")))标记)
这样两个项目编译时,外部库函数会被链接到同一地址,自然实现复用。
3. 生成符号定义链接脚本替代头文件
如果不想用--just-symbols,可以用nm工具提取project1的符号地址,生成链接器可识别的符号定义文件:
- 从project1的ELF文件中提取目标符号:
nm -g project1.elf | grep external_add > external_syms.txt - 将结果整理成链接脚本片段
external_lib_syms.ld:PROVIDE(external_add = 0x00008d7fe0089000); - 在project2的链接脚本中引入该文件:
INCLUDE "external_lib_syms.ld"
同样需要确保project2不链接external_lib的静态库,仅保留头文件声明。
4. 编译为位置无关共享库(针对支持动态链接的平台)
如果你的嵌入式平台支持动态链接(如ARM Cortex-A、带MMU的RISC-V),可以将external_lib编译为**位置无关代码(PIC)**的共享库:
- 编译external_lib时添加
-fPIC选项,链接时用-shared生成共享库:arm-none-eabi-gcc -fPIC -c external_add.c -o external_add.o arm-none-eabi-gcc -shared -o libexternal.so external_add.o - 让project1和project2都链接该共享库,运行时由动态链接器加载到内存,实现代码共享。注意需确保平台支持动态链接且有足够资源。
内容的提问来源于stack exchange,提问作者Wanderer

