使用clang链接存在内部符号冲突的双内核静态库生成单可执行文件
解决方案
问题1:思路可行性与实现方式
你的思路完全可行,不需要修改源代码中的函数名,有两种成熟的实现方案适配clang编译链:
方案1:编译阶段控制符号可见性
- 编译内核A的所有代码时,添加编译参数
-fvisibility=hidden,仅将两个内核需要跨内核调用的交互接口用__attribute__((visibility("default")))显式标记为全局可见 - 编译内核B的所有代码时,同样添加
-fvisibility=hidden参数,仅对外暴露必要的交互接口 - 公共依赖的stub函数、共享内存操作代码单独抽离为公共编译单元,正常编译即可,不受可见性参数影响
- 原理:静态库内部未显式标记为全局可见的同名函数会被处理为局部符号,链接时仅会在自身库内部解析,不会出现跨库绑定的问题
方案2:静态库后处理本地化符号
如果不方便修改现有编译参数,可以对已生成的静态库做后处理:
- 处理内核A的静态库:
objcopy --localize-hidden libcoreA.a libcoreA_local.a,可配合--keep-global-symbol=xxx参数保留需要对外暴露的全局符号,其余全部转为局部符号 - 用同样的命令处理内核B的静态库,得到
libcoreB_local.a - 最终链接时使用处理后的两个静态库即可,局部符号的解析优先级永远高于全局符号,不会产生冲突
问题2:替代方案
如果上述方案不符合你的使用场景,可以选择以下两种替代方案,同样满足clang编译、输出单个可执行文件的约束:
- 符号前缀批量重命名:用objcopy给其中一个静态库的所有全局符号添加唯一前缀,不需要修改源代码。例如对内核A的静态库执行
objcopy --prefix-symbols=coreA_ libcoreA.a libcoreA_prefixed.a,在模拟启动的main函数中调用内核A入口时改为调用coreA_<原入口函数名>即可,两个库的同名函数因为前缀不同不会产生冲突 - 可重定位目标文件隔离:把每个内核的所有编译单元用
ld -r命令合并为单个可重定位目标文件,通过自定义链接脚本将两个内核的代码段、数据段分配到不同的地址范围,同时指定符号解析的作用域,两个内核的内部符号完全隔离,仅显式导出的交互接口可跨内核访问
内容的提问来源于stack exchange,提问作者Gileos
相关产品推荐
相关产品推荐

