将xo65目标文件与ELF、LLVM IR文件混合链接的可行方案有哪些?
混合链接LLVM编译产物与CC65 xo65目标文件的可选方案
你遇到的ld.lld报错是因为LLVM的链接器不识别CC65生成的xo65格式目标文件,可参考以下方案解决:
方案1:切换最终链接器为CC65的ld65(最稳定)
这个方案改动最小,适合大多数场景:
- 先单独完成LLVM侧所有输入的LTO编译,输出CC65兼容的xo65格式目标文件:
llvm-mos/bin/clang \ --config llvm-mos-sdk/build/commodore/64.cfg \ -O2 \ -fno-use-lld \ -emit-obj \ -o _build/llvm_all.o \ _build/dir.c.ll \ _build/interrupt.c.ll \ _build/main.c.ll \ _build/dir.s.o \ _build/panic.ll.bc \ rs/target/release/deps/chip8_engine-2a1bf4bc9333b677.bc \ rs/target/release/deps/chip8_c64-a95cc9a5a3e99697.bc
llvm-mos后端原生支持输出xo65格式目标,上述命令生成的_build/llvm_all.o可以直接被ld65识别。
2. 用ld65将LLVM侧输出的目标文件和CC65编译的xo65目标统一链接,输出最终prg文件:
ld65 \ -C llvm-mos-sdk/build/commodore/64.cfg \ _build/llvm_all.o \ _build/native/readdir.c.o \ 其他CC65编译的.o文件 \ -o _build/chip8.prg
注意两边调用约定要对齐,跨侧调用的函数需要手动匹配CC65的__fastcall__或__cdecl__约定,避免参数传递错误。
方案2:将CC65目标封装为LLVM兼容的ELF文件
如果你需要保留原有的LLVM LTO+ld.lld的完整链路,可以用二进制封装的方式引入CC65产物:
- 先单独链接所有CC65目标文件,生成固定地址的纯二进制片段和符号表:
编写一个临时链接脚本cc65_fragment.cfg,预留的代码/数据段地址要和llvm-mos的链接脚本中空闲地址完全对齐,避免地址冲突,然后执行:
ld65 \ -C cc65_fragment.cfg \ _build/native/readdir.c.o \ 其他CC65编译的.o文件 \ -o _build/cc65_fragment.bin \ -m _build/cc65_symbols.map
- 用llvm-objcopy将二进制片段封装为llvm-mos兼容的ELF目标文件:
llvm-mos/bin/llvm-objcopy \ -I binary \ -O elf32-mos \ --binary-architecture mos \ _build/cc65_fragment.bin \ _build/cc65_fragment.o
- 将生成的
_build/cc65_fragment.o添加到你原有的clang编译命令的输入列表中即可正常编译。同时需要根据cc65_symbols.map中的符号地址,编写头文件声明CC65侧导出的函数、变量,供LLVM侧代码调用。
方案3:反汇编重写(仅适合小体积目标)
如果你的CC65目标文件体积很小,也可以用da65将xo65文件反汇编为汇编代码,手动调整语法适配LLVM-MOS汇编器后,作为汇编输入加入原有编译链路。
内容的提问来源于stack exchange,提问作者Cactus
相关产品推荐
相关产品推荐

