能否从单个源文件按ELF段生成多个目标文件?
解决方案:通过GNU Binutils拆分目标文件(无需额外工具)
可以利用GCC工具链自带的objcopy(属于GNU Binutils,不属于elfutils类外部工具),从单个源文件生成的目标文件中按ELF段提取内容,生成独立的目标文件,完美适配你的受控构建环境和嵌入式空间需求。
具体步骤
假设你的源文件dynamic_syms.c通过宏将符号指定到自定义段(比如__my_initcalls):
#define INITCALL(fn) \ static void fn(void) __attribute__((used, section("__my_initcalls"))) INITCALL(foo_init) { /* 初始化逻辑 */ } INITCALL(bar_init) { /* 初始化逻辑 */ } // 更多注册符号
编译源文件为完整目标文件
先将源文件编译成包含所有段的目标文件:# 替换为你的交叉编译工具链前缀 arm-linux-gnueabihf-gcc -c dynamic_syms.c -o dynamic_syms.o按ELF段提取独立目标文件
使用objcopy的--only-section参数,提取指定段到单独的目标文件:arm-linux-gnueabihf-objcopy --only-section=__my_initcalls dynamic_syms.o initcalls.o若源文件包含多个自定义段(比如
__my_cmds),可重复此命令生成多个目标文件:arm-linux-gnueabihf-objcopy --only-section=__my_cmds dynamic_syms.o commands.o归档独立目标文件为小型静态库
将提取出的目标文件单独归档,避免影响其他库:arm-linux-gnueabihf-ar rcs libinitcalls.a initcalls.o链接时精准保留符号
链接主二进制时,仅对这个小型库使用-Wl,-whole-archive,确保段内所有符号被保留,同时不浪费空间:arm-linux-gnueabihf-gcc main.o -o firmware -L. \ -Wl,-whole-archive -linitcalls -Wl,-no-whole-archive \ -lother_required_libs
为什么这个方案适合你
- 无需额外工具:
objcopy是GCC交叉编译工具链的标准组件,受控环境通常允许使用。 - 无空间浪费:仅对包含目标段的小型库启用
whole-archive,不会引入无关符号。 - 无需提前知晓符号名:仅需指定段名即可提取所有对应符号,避开GCC 8.4不支持通配
--undefined的限制。 - 灵活拆分:可按任意ELF段拆分目标文件,适配类似U-Boot命令注册、Linux initcall的动态符号场景。
验证方法
可以用objdump -h initcalls.o查看提取后的目标文件,确认仅包含指定段;再用nm -D firmware检查主二进制中是否存在所有目标符号。
内容的提问来源于stack exchange,提问作者MysteryMoose
相关产品推荐
相关产品推荐

