4. 设备树编译器(DTC):安装、使用与反编译
设备树编译器(Device Tree Compiler,DTC)是设备树开发流程中的核心工具,负责将人类可读的 .dts 源文件编译为二进制 .dtb 文件,也支持反向操作。本章系统讲解 DTC 的安装、编译与反编译方法,并深入分析其工作流程。
核心概念: DTC 是设备树生态的“翻译官”,它将文本描述转换为内核可解析的二进制结构,是连接设备树源文件与内核驱动 probe 调用的关键桥梁。
4.1 DTC 的安装
DTC 通常作为独立工具或内核源码的一部分提供。以下是三种主流安装方式:
| 安装方式 | 命令/步骤 | 适用场景 |
|---|---|---|
| 包管理器安装 | sudo apt-get install device-tree-compiler (Debian/Ubuntu)sudo yum install dtc (CentOS/RHEL) |
快速开发,版本稳定 |
| 内核源码编译 | make scripts 或 make dtc (在内核根目录) |
与内核版本严格对齐 |
| 源码编译安装 | 从 git://git.kernel.org/pub/scm/utils/dtc/dtc.git 克隆,执行 make && sudo make install |
获取最新特性或修复 |
验证安装: 执行
dtc --version 查看版本号,输出类似 Version: DTC 1.6.1 即表示安装成功。
4.2 DTC 编译流程:从 .dts 到 .dtb
编译过程将设备树源文件转换为二进制格式,供内核 Bootloader 或内核解析。基本命令格式如下:
dtc -I dts -O dtb -o output.dtb input.dts
参数说明:
-I dts:指定输入格式为.dts源文件-O dtb:指定输出格式为.dtb二进制文件-o output.dtb:指定输出文件名-@:生成带符号表的.dtb,支持插件(overlay)-H epapr:指定 phandle 格式(可选)
以下是一个完整的编译示例:
# 编译简单设备树
dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 编译并保留符号表(用于设备树插件)
dtc -I dts -O dtb -@ -o myboard.dtb myboard.dts
# 编译时输出警告信息
dtc -I dts -O dtb -W all -o myboard.dtb myboard.dts
常见错误: 如果
.dts 文件中包含 #include 预处理指令,必须先使用 C 预处理器展开:cpp -P -I include_path input.dts temp.dts,再编译 temp.dts。现代 DTC 支持 -i 参数指定包含路径。
4.3 反编译:从 .dtb 到 .dts
反编译是将二进制 .dtb 还原为可读的 .dts 源文件,常用于调试、逆向分析或验证编译结果。基本命令:
dtc -I dtb -O dts -o output.dts input.dtb
反编译示例:
# 标准反编译
dtc -I dtb -O dts -o decompiled.dts myboard.dtb
# 反编译并保留所有节点(包括空节点)
dtc -I dtb -O dts -f -o decompiled.dts myboard.dtb
# 反编译并显示地址信息
dtc -I dtb -O dts -S -o decompiled.dts myboard.dtb
实用技巧: 反编译时添加
-@ 参数可以保留插件元数据;使用 -V 17 指定版本号,确保与内核兼容。
4.4 DTC 工作流程架构
下图展示了 DTC 从源文件到二进制文件的完整处理流程,以及反编译的逆向路径:
4.5 编译与反编译对比
| 操作 | 输入格式 | 输出格式 | 典型用途 | 注意事项 |
|---|---|---|---|---|
| 编译 | .dts |
.dtb |
生成内核可加载的设备树 | 需先预处理 #include |
| 反编译 | .dtb |
.dts |
调试、逆向、验证编译结果 | 可能丢失注释和格式 |
| 编译(带插件) | .dts |
.dtb + 符号表 |
支持设备树插件(overlay) | 必须加 -@ 参数 |
| 反编译(保留元数据) | .dtb |
.dts |
分析插件结构 | 加 -@ 保留插件信息 |
4.6 实战案例:完整编译与反编译流程
以下是一个完整的实战示例,展示从编写 .dts 到反编译验证的全过程:
# 1. 编写简单的设备树源文件
cat < myboard.dts
/dts-v1/;
/ {
compatible = "mycompany,myboard";
#address-cells = <1>;
#size-cells = <1>;
uart@10000000 {
compatible = "ns16550";
reg = <0x10000000 0x1000>;
interrupts = <33>;
};
};
EOF
# 2. 编译为 .dtb
dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 3. 查看编译后的二进制大小
ls -lh myboard.dtb
# 4. 反编译验证
dtc -I dtb -O dts -o myboard_decompiled.dts myboard.dtb
# 5. 对比原始与反编译文件
diff myboard.dts myboard_decompiled.dts
调试技巧: 使用
dtc -I dtb -O dts -V 17 -@ myboard.dtb 可以查看 .dtb 的完整结构,包括 phandle 和插件元数据。添加 -W no-unit_address_vs_reg 可抑制某些警告。
4.7 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 编译报错“syntax error” | .dts 文件格式错误 |
检查分号、花括号、引号是否匹配 |
| 反编译输出为空 | .dtb 文件损坏或版本不兼容 |
使用 file 命令检查文件类型,尝试 -V 17 参数 |
| 预处理错误 | 缺少包含路径或头文件 | 使用 -i 指定包含目录,或手动 cpp -P 预处理 |
| 插件编译失败 | 未使用 -@ 参数 |
编译时添加 -@ 生成符号表 |
重要提示: 反编译得到的
.dts 文件会丢失原始注释和部分格式信息,不能作为修改后重新编译的可靠源文件。始终保留原始 .dts 源文件作为唯一权威版本。
4.8 本章小结
DTC 是设备树开发中不可或缺的工具,掌握其安装、编译和反编译操作是进行设备树驱动开发的基础。通过本章学习,你应该能够:
- 在主流 Linux 发行版上安装 DTC
- 使用
dtc命令将.dts编译为.dtb - 使用
dtc -I dtb -O dts反编译.dtb为可读格式 - 理解编译与反编译的完整流程和适用场景
- 处理常见的编译和反编译错误