llvm-objdump是LLVM官方标准反汇编工具,支持ELF、MachO、COFF/PE等格式,需显式加-d选项才能反汇编;它基于LLVM MC层解析,跨平台一致性强,可输出带IR关联线索的注释,但默认不显示指令字节,也不自动符号化,遇stripped文件需配合llvm-readobj或先解包处理。

用 llvm-objdump 反汇编 ELF/MachO/PE 目标文件
LLVM 不提供传统意义上的“反汇编器”独立命令名(比如 objdump 那样直白),但 llvm-objdump 就是它的标准反汇编工具,支持 ELF、MachO、COFF/PE 等主流目标格式。它不依赖系统 binutils,纯靠 LLVM MC 层解析二进制结构,因此跨平台一致性强,且能输出带 IR 关联线索的注释(如符号绑定、重定位点)。
常见错误现象:直接运行 llvm-objdump func.o 却只看到符号表或段头,没反汇编代码——这是因为默认不启用反汇编,必须显式加 -d 或 --disassemble。
-
llvm-objdump -d func.o:反汇编所有可执行节(如.text) -
llvm-objdump -d --arch-name=arm64 func.o:强制指定架构(当目标文件无明确 triple 或 host 不匹配时必需) -
llvm-objdump -d -print-imm-hex func.o:十六进制显示立即数,避免符号混淆(比如mov x0, #0x1000而不是mov x0, #4096) -
llvm-objdump -d --mattr=+v8.5a func.o:启用特定扩展指令集支持(否则遇到新指令会报invalid instruction encoding)
为什么 llvm-mc -disassemble 通常不适用
llvm-mc 的反汇编能力仅限于“裸指令流”,即它要求输入是**纯机器码字节序列**(如从 .data 节提取的一段二进制),不能自动识别目标文件格式、节头、符号表或重定位信息。对 .o 文件直接跑 llvm-mc -disassemble func.o 会失败,报错类似 error: invalid object file format。
真正该用 llvm-mc 的场景是:
- 你有一段 hex dump(如
0f 20 00 d5),想快速看对应 ARM64 指令:echo "0f 20 00 d5" | llvm-mc -arch=arm64 -disassemble - 从内存 dump 中截取一段 raw bytes,需要离线分析
拿目标文件去喂 llvm-mc 是走错了工具链分支。
遇到 “unknown symbol” 或 “relocation applied” 怎么办
反汇编输出里出现类似 bl <unknown symbol></unknown> 或 adrp x0, #0x0 ; R_AARCH64_ADR_PREL_PG_HI21 sym,说明该指令含重定位项,而 llvm-objdump 默认不解析符号上下文。
解决办法是补上符号表支持:
-
llvm-objdump -d -t func.o:同时打印符号表(-t),帮助你手动对照地址 -
llvm-objdump -d --symbolize func.o:尝试自动符号化(需目标文件含调试信息或符号未 strip) - 若符号已被 strip,只能靠
llvm-readobj -sections func.o查节地址 + 手动计算偏移,或回退到链接后的可执行文件再反汇编
与 GNU objdump 的关键差异点
两者输出风格和默认行为不同,容易误判结果是否“正确”:
-
llvm-objdump默认不显示指令编码字节(GNU 默认显示),要加-z才显示:llvm-objdump -d -z func.o - GNU
objdump对 PIC 代码常省略 GOT/PLT 细节,而llvm-objdump会明确标出R_X86_64_GOTPCREL类型重定位 - ARM64 下,GNU 可能把
adrp+add合并显示为一条伪指令,LLVM 则严格按实际机器码拆成两条 - 性能影响:对超大目标文件(>100MB),
llvm-objdump内存占用略高,因它构建完整 MCInst 链;此时可加--no-show-raw-insn减少开销
真正难处理的是 stripped 的 thin archive(.a)或 LTO bitcode 混合目标文件——这类文件得先用 llvm-ar 解包,再逐个 llvm-objdump,不能指望一键全扫。

















