4. 设备树编译与反编译

设备树源文件(DTS)本身只是人类可读的文本描述,真正被内核解析的是二进制设备树块(DTB)。在跨平台迁移工程中,dtc(Device Tree Compiler)工具链是连接“可读描述”与“可执行数据”的核心桥梁。掌握编译与反编译,不仅能验证迁移后的设备树是否合法,还能通过反编译逆向分析原厂固件中的硬件配置,是迁移工作中最常用的手段之一。

一、dtc工具链与核心参数

dtc 通常随内核源码的 scripts/dtc 目录提供,也可通过发行版包管理器安装(如 apt install device-tree-compiler)。它支持三种主要工作模式:DTS→DTB 编译、DTB→DTS 反编译、以及 DTS 语法检查。常用参数如下:

参数作用典型场景
-I dts / -I dtb指定输入格式编译或反编译时明确源类型
-O dtb / -O dts指定输出格式决定生成二进制还是文本
-o output指定输出文件避免默认输出到 stdout
-@生成符号节点(__symbols__)支持运行时 overlay 叠加
-i include_dir添加头文件搜索路径跨目录引用 .dtsi
-W no-unit_address_vs_reg关闭指定警告抑制迁移中的非致命告警

二、DTS到DTB的编译过程

编译并非简单的文本转换,而是包含预处理、语法解析、语义检查、扁平化四个阶段。C 预处理器先处理 #include 与宏,dtc 再将树形结构编码为 FDT(Flattened Device Tree)格式,最终生成 DTB。典型命令如下:

# 基础编译
dtc -I dts -O dtb -o board.dtb board.dts

# 带头文件路径与符号节点
dtc -I dts -O dtb -@ -i include/ -o board.dtb board.dts

# 内核构建系统方式(推荐用于正式迁移)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

编译成功后,DTB 头部包含 magic(0xd00dfeed)、总大小、结构块偏移、字符串块偏移等字段。内核启动时由 bootloader 将该二进制块传入,内核再展开为 device_node 树。迁移时若目标平台 bootloader 对 DTB 大小或对齐有要求,需特别关注头部字段。

DTS → DTB → DTS 编译与反编译数据流 DTS / DTSI 文本源文件 #include / 宏 C 预处理器 cpp / gcc -E 展开头文件 dtc 编译器 语法/语义检查 FDT 扁平化 DTB 二进制 magic 0xd00dfeed 结构块 + 字符串块 dtc -I dtb -O dts 反编译还原 生成可读 DTS 反编译 DTS 节点/属性还原 phandle 重建 常见错误与调试 语法错误 / 未定义引用 / 地址冲突 dtc -I dts -O dts 语法自检

三、DTB到DTS的反编译方法

反编译是迁移工程中的“逆向侦察”手段。当拿到原厂固件或目标板 DTB 却缺少源码时,可用以下命令还原为可读文本:

# 反编译为 DTS
dtc -I dtb -O dts -o recovered.dts board.dtb

# 查看 DTB 头部信息
fdtdump board.dtb | head -40

# 从运行中的系统导出当前设备树
dtc -I fs -O dts -o live.dts /proc/device-tree

反编译结果会保留节点层级、reg 地址、compatible 字符串、中断号等关键信息,但注释、宏定义和 include 关系会丢失。迁移时应将反编译结果作为参考,重新整理为带 .dtsi 分层结构的源码,而不是直接用于生产。

四、常见编译错误与调试技巧

  • 语法错误:缺少分号、大括号不匹配、属性名拼写错误。dtc 会给出文件名与行号,优先检查报错行上方。
  • 未定义引用:使用 &label 但对应节点未定义,或 .dtsi 未被包含。检查 include 路径与标签名。
  • 地址/单元冲突:reg 属性长度与 #address-cells、#size-cells 不匹配,导致解析异常。
  • 重复节点:同一路径下节点名重复,dtc 会报 duplicate node name。
  • 警告淹没:使用 -W no-xxx 关闭非致命警告,聚焦真正错误。
调试建议:先用 dtc -I dts -O dts board.dts 做纯语法自检,不生成 DTB;再逐步加入 -@、-i 等参数定位问题。反编译得到的 DTS 可用于与迁移后源码做 diff,快速发现属性遗漏。
注意:反编译生成的 DTS 中 phandle 为数字,直接修改后重新编译可能因 phandle 变化导致引用错乱。迁移时应使用标签引用而非硬编码 phandle。

五、迁移场景复盘

某 ARM64 平台迁移中,原厂 DTB 反编译后发现 ethernet@fe300000 节点缺少 phy-mode 属性,而目标板原理图要求 RGMII。若直接使用原 DTB,网口无法工作。通过反编译对比、补充属性、重新编译并验证,最终解决。这说明:编译与反编译不仅是工具操作,更是迁移中“验证—对比—修正”闭环的关键环节。

掌握 dtc 工具链后,建议将编译命令固化为 Makefile 或脚本,配合 dtc -I dtb -O dts 做版本对比,形成可重复、可追溯的设备树迁移流程。