llvm后端默认支持生成elf目标文件,只需架构适配并走asmprinter→mcobjectstreamer→elfobjectwriter流程;clang -c或llc -filetype=obj可直接产出标准et_rel格式.o文件。

LLVM后端默认就能生成ELF目标文件,不需要额外实现链接器或重写文件格式逻辑——只要目标架构支持(如x86_64、aarch64、riscv64等),且编译流程走到AsmPrinter之后的MCStreamer和ObjectWriter阶段,就会自然产出.o文件,即ELF Relocatable格式。
clang -c 生成的 .o 就是 ELF 目标文件
最直接的方式就是用clang加-c选项:
-
clang -target aarch64-linux-gnu -c hello.c -o hello.o→ 输出标准ELF32/ELF64可重定位文件 -
file hello.o会显示ELF 64-bit LSB relocatable, ARM aarch64 -
readelf -h hello.o可确认e_type == ET_REL,这是ELF Relocatable的标志 - 省略
-target时走默认三元组(通常是x86_64-pc-linux-gnu),仍输出ELF
注意:-c跳过链接,只做编译+汇编+目标文件生成,这正是LLVM后端AsmPrinter → MCObjectStreamer → ELFObjectWriter整条流水线的典型出口。
自定义后端必须注册 ELFObjectWriter
如果你在写新架构后端(比如EM_RISCVN),光有指令选择和汇编打印还不够,.o文件要能被ld.lld或binutils识别,必须让LLVM知道怎么序列化该架构的ELF结构:
- 需在
llvm/lib/Object/ELF.cpp中为e_machine值(如EM_RISCVN)注册getELFRelocationTypeName分支 - 要在
llvm/include/llvm/BinaryFormat/ELF.h里声明新的EM_*常量,并确保它不与现有值冲突 -
ELFObjectFile<elft>::getArch()</elft>必须返回对应Triples::riscvn这类枚举,否则llvm-readobj无法识别架构 - 没做这些,
llc -filetype=obj可能静默失败,或生成的.o被readelf报Invalid ELF header
llc 工具也能生成 ELF,但要注意 -filetype 参数
llc作为LLVM IR到目标码的独立编译器,同样支持ELF输出,但行为比clang更底层、更易出错:
-
llc -mtriple=aarch64-linux-gnu -filetype=obj input.ll -o out.o→ 正确生成ELF - 漏掉
-filetype=obj,默认输出汇编文本(.s),不是ELF -
-filetype=asm或-filetype=null都不会触发ObjectWriter,也就没有ELF - 若IR里用了未定义的全局符号,
llc可能不报错但生成的ELF含非法重定位项,后续链接时报undefined reference
本质是:-filetype=obj才启用MCObjectStreamer后端,进而调用ELFObjectWriter;其他模式走的是MCAsmStreamer,只写文本。
常见错误:生成了文件但 readelf 报错或 objdump 无节区
这类问题基本指向ELF头或节区表损坏,根源往往不在后端逻辑,而在配置或数据流断点:
-
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start→llc没走ObjectWriter路径,或TargetMachine没正确设置Options.MCOptions.AsmVerbose = false等影响二进制输出的开关 -
objdump -d out.o显示No architecture specified→Triple未传入或解析失败,导致ELFObjectFile::getArch()返回Triple::UnknownArch - 节区数量为0或
.text大小为0 →AsmPrinter没emit任何MCInst,常见于SelectionDAGISel未匹配指令,或MachineFunctionPass提前清空了指令列表 - 用
lld链接时报unknown symbol type→ 重定位类型未在ELFRelocs/XXX.def中定义,或getELFRelocationTypeName未覆盖该Machine分支
ELF不是“生成出来就行”的格式;它要求架构标识、重定位语义、节区布局全部对齐工具链预期。哪怕只是新增一个EM_FOO,漏掉ELFYAML.cpp里的enumCase,llvm-objcopy --yaml-input就会失败——这种细节恰恰最容易在调试时被跳过。











