arm-none-eabi开启-flto编译时如何重定义目标文件malloc等符号
问题原因
objcopy重定义符号失效是LTO(链接时优化)的机制导致的。开启-flto后,编译生成的test.o不是常规可重定位目标文件,符号表中的__gnu_lto_slim标记说明这是瘦LTO对象,内部存储的是GCC的GIMPLE中间码而非最终机器码,malloc、free这类外部符号的引用没有写入常规ELF符号表,全部存在.gnu.lto_*开头的专属段中,objcopy无法识别这类未落地的符号引用,重定义操作自然无效。
这类符号的解析、重定位动作会被推迟到链接阶段,由链接器配合LTO插件统一处理,对编译阶段生成的单个.o文件做符号重定义属于选错了操作时机。
可行解决方案
按易用性、侵入性从低到高排序:
- 最推荐:链接阶段通过链接器参数重定义符号
不需要在编译后对单个.o文件执行objcopy,直接在最终链接命令中追加参数,LTO优化完成、链接器处理符号时会自动将所有malloc、free的引用替换为自定义函数,完全兼容-flto场景:
该方案不需要修改现有编译参数、不需要调整源码,是侵入性最低的实现方式。-Wl,--defsym=malloc=own_malloc -Wl,--defsym=free=own_free - 次选:编译阶段通过宏提前替换符号
如果不方便调整链接参数,可以在编译选项中追加宏定义,在预处理阶段就完成符号名替换,该逻辑对LTO中间态同样生效:
现有编译参数已经加了-Dmalloc=own_malloc -Dfree=own_free-fno-builtin,不用担心编译器将malloc识别为内置函数跳过替换,只需保证宏定义在所有头文件包含逻辑之前生效即可。 - 备选:最终链接完成后再执行objcopy操作
如果一定要用objcopy做符号重定义,不要对单个编译生成的.o操作,等所有编译、LTO流程走完,生成完整的最终ELF文件(如最终固件镜像、所有.o预链接生成的目标文件)后,再对该最终文件执行--redefine-sym命令,此时所有符号已经写入常规符号表,objcopy可以正常识别替换。 - 不推荐:关闭瘦LTO模式生成带完整符号的.o
编译时追加-fno-lto-slim参数,生成的.o文件会同时包含LTO中间码、常规ELF符号和重定位段,原objcopy命令可以正常生效,但该参数会大幅增大中间文件体积,拖慢编译速度,非必要不使用。
注意:自定义实现的
own_malloc、own_free必须用extern "C"修饰,保证符号为C风格命名,否则C++的名字修饰机制会导致最终链接时找不到对应符号。
内容的提问来源于stack exchange,提问作者Ding Brains
相关产品推荐
相关产品推荐

