LLVM 开发指南 / 第 11 章:MC 层与汇编
第 11 章:MC 层与汇编
“MC 层是 LLVM 与硬件之间的最后一道桥梁。”
11.1 MC 层概述
MC(Machine Code)层是 LLVM 中最接近硬件的层次,负责:
- MCInst 表示机器指令
- 汇编器(Assembler):文本汇编 → 机器码
- 反汇编器(Disassembler):机器码 → 文本汇编
- 目标文件生成:ELF / MachO / COFF / WebAssembly
LLVM IR
│
▼ (CodeGen)
MachineInstr
│
▼ (AsmPrinter)
MCInst
│
├──► MCAsmStreamer ──► 汇编文本 (.s)
│
└──► MCObjectStreamer ──► 目标文件 (.o)
├── ELF
├── MachO
├── COFF
└── Wasm
11.2 MCInst
MCInst 是 MC 层的核心指令表示。
11.2.1 MCInst 结构
// MCInst 包含:
// 1. 操作码(Opcode)— 目标特定的操作码编号
// 2. 操作数列表(Operands)— 寄存器、立即数、内存引用等
// 示例:x86 的 "addl %ecx, %eax"
MCInst Inst;
Inst.setOpcode(X86::ADD32rr);
Inst.addOperand(MCOperand::createReg(X86::EAX)); // 目标寄存器
Inst.addOperand(MCOperand::createReg(X86::ECX)); // 源寄存器
// 示例:x86 的 "addl $42, %eax"
MCInst Inst;
Inst.setOpcode(X86::ADD32ri);
Inst.addOperand(MCOperand::createReg(X86::EAX));
Inst.addOperand(MCOperand::createImm(42));
11.2.2 MCOperand 类型
| 类型 | 创建方法 | 说明 |
|---|---|---|
| 寄存器 | MCOperand::createReg(Reg) | 物理寄存器编号 |
| 立即数 | MCOperand::createImm(Val) | 整数常量 |
| 浮点 | MCOperand::createFPImm(Val) | 浮点常量 |
| 表达式 | MCOperand::createExpr(Expr) | 符号表达式 |
11.3 MCStreamer
MCStreamer 是 MC 层的输出抽象:
11.3.1 两种输出流
// 1. 汇编输出 (MCAsmStreamer)
// 输出人类可读的汇编文本
// "addl %ecx, %eax\n"
// 2. 目标文件输出 (MCObjectStreamer)
// 输出二进制机器码
// → ELF / MachO / COFF
# 生成汇编
llc test.bc -o test.s
# 生成目标文件
llc -filetype=obj test.bc -o test.o
# 生成汇编(从 Clang)
clang -S test.c -o test.s
# 生成目标文件(从 Clang)
clang -c test.c -o test.o
11.4 MC 汇编解析器
11.4.1 使用 llvm-mc
# 汇编文本 → 目标文件
echo 'addl %ecx, %eax' | llvm-mc -triple=x86_64 --filetype=obj -o test.o
# 汇编文本 → 汇编(标准化)
echo 'addl %ecx, %eax' | llvm-mc -triple=x86_64 --show-encoding
# 反汇编
llvm-objdump -d test.o
# 使用 llvm-mc 作为汇编器
llvm-mc -triple=x86_64 test.s -filetype=obj -o test.o
11.4.2 使用 llvm-objdump
# 反汇编整个文件
llvm-objdump -d program
# 反汇编特定段
llvm-objdump -d -j .text program
# 显示源码与汇编对应
llvm-objdump -S program
# 显示符号表
llvm-objdump --syms program
# 显示重定位信息
llvm-objdump -r test.o
# 显示节头
llvm-objdump -h program
# 显示所有段的内容
llvm-objdump -s program
11.4.3 使用 llvm-nm
# 查看符号表
llvm-nm program
# 输出格式:
# 地址 类型 名称
# 004000 T main
# 004010 T add
# U printf (未定义/外部符号)
11.5 目标文件格式
11.5.1 ELF(Linux)
# ELF 头信息
llvm-readelf -h program
# 节头表
llvm-readelf -S program
# 程序头表(段信息)
llvm-readelf -l program
# 重定位表
llvm-readelf -r test.o
# 动态符号
llvm-readelf --dyn-syms program
# DWARF 调试信息
llvm-readelf --debug-dump=info program
11.5.2 MachO(macOS)
# 使用 llvm-objdump 查看 MachO
llvm-objdump -h program.dylib
llvm-objdump --macho -d program
# 使用 llvm-readobj
llvm-readobj --macho-data program
11.5.3 COFF(Windows)
# 使用 llvm-readobj
llvm-readobj --coff-basereloc program.exe
llvm-readobj --coff-imports program.exe
llvm-readobj --coff-exports program.exe
11.6 llvm-mc 工具
# 汇编 → 目标文件
llvm-mc -triple=x86_64 test.s -filetype=obj -o test.o
# 汇编 → 标准汇编(规范化)
llvm-mc -triple=x86_64 test.s -show-encoding
# 查看指令编码
echo "nop" | llvm-mc -triple=x86_64 --show-encoding
# 显示指令信息
llvm-mc -triple=x86_64 -mattr=+avx2 --show-encoding <<< "vpaddb %ymm0, %ymm1, %ymm2"
11.7 链接器 (LLD)
LLD 是 LLVM 的高性能链接器,可替代 GNU ld。
# 使用 LLD 链接
clang -fuse-ld=lld test.o -o test
# 直接使用 LLD
ld.lld test.o -o test
# 生成共享库
ld.lld -shared test.o -o libtest.so
# 静态链接
ld.lld -static test.o -o test
# 查看链接过程
ld.lld --verbose test.o -o test 2>&1
# 生成 map 文件
ld.lld -Map=output.map test.o -o test
# 比较链接器速度
time ld.lld test.o -o test # LLD (快)
time ld test.o -o test # GNU ld (慢)
11.7.1 LLD 特性
| 特性 | 说明 |
|---|---|
| 速度快 | 比 GNU ld 快 2-10 倍 |
| 内存效率 | 多线程并行 |
| 兼容性 | 兼容 GNU ld 命令行 |
| LTO 支持 | 原生支持 LLVM LTO |
| 调试信息 | 高效处理 DWARF |
11.8 本章小结
| 工具 | 功能 | 命令示例 |
|---|---|---|
llvm-mc | 汇编/反汇编 | llvm-mc -triple=x86_64 test.s -filetype=obj |
llvm-objdump | 反汇编/查看 | llvm-objdump -d program |
llvm-nm | 符号表 | llvm-nm program |
llvm-readelf | ELF 分析 | llvm-readelf -h program |
llvm-readobj | 通用目标文件分析 | llvm-readobj --all program |
llvm-strip | 剥离符号 | llvm-strip program |
llvm-objcopy | 目标文件操作 | llvm-objcopy --strip-debug |
ld.lld | 链接器 | ld.lld test.o -o test |
扩展阅读
- LLVM MC Documentation — MC 层文档
- ELF Spec — ELF 格式规范
- LLD Documentation — LLD 链接器文档
下一章: 第 12 章:LLVM 库与 API — 学习 libLLVM、libClang 和 LLVM C/C++ API。