2. 镜像类型与格式解析

在VxWorks工程中,编译产物并不是一个“万能镜像”,而是根据运行位置(RAM还是ROM/Flash)、是否包含符号表、是否压缩以及启动方式(直接跳转还是自解压搬运)派生出多种镜像文件。理解这些镜像的组成与差异,是后续配置启动链、划分存储布局、选择烧写方式的前提。本节围绕最常见的四类镜像——VxWorks、VxWorks.st、VxWorks_rom、VxWorks_romCompress——从文件结构、加载行为到适用场景逐一解析。

一、镜像的公共组成:从ELF到可引导映像

无论哪种镜像,其源头都是链接器输出的ELF格式内核映像。ELF中包含代码段(.text)、只读数据段(.rodata)、已初始化数据段(.data)、未初始化数据段(.bss)、符号表(.symtab/.strtab)以及调试信息(.debug_*)。构建系统通过elfToBin、vxImageConvert等工具,把ELF“转换”为不同用途的二进制映像。转换过程中主要做三件事:

  • 剥离或保留符号表:决定镜像是否可用于在线调试与符号解析。
  • 确定加载地址与入口地址:决定镜像被搬运到RAM的哪个位置、从哪个地址开始执行。
  • 附加引导头或压缩数据:决定镜像能否被BootROM直接识别、是否需要自解压。

因此,四类镜像的差异本质上就是“符号表有无 + 运行位置 + 压缩与否”三个维度的组合。下面这张图给出了它们从同一ELF源派生出的结构关系与加载路径。

链接器输出 ELF 内核映像 .text / .data / .bss / .symtab / .debug elfToBin / vxImageConvert 转换 VxWorks 含符号表 · 未压缩 加载到 RAM 运行 调试首选 体积最大 VxWorks.st 含符号表 · 未压缩 带启动头,可自引导 支持在线符号调试 常用于开发阶段 VxWorks_rom 无符号表 · 未压缩 直接在 ROM 中执行 .data 需搬运到 RAM 适合小容量固化 VxWorks_romCompress 无符号表 · 压缩 ROM 中存压缩体 启动时解压到 RAM 节省 Flash 空间 运行位置与启动行为对比 RAM 中运行 RAM 中运行 ROM 中执行 + RAM 数据 解压后 RAM 中运行 选择依据:① 是否需要符号调试 → 选 VxWorks / VxWorks.st;② 是否直接固化在 ROM 执行 → 选 VxWorks_rom; ③ Flash 容量紧张 → 选 VxWorks_romCompress;④ 生产固化且空间充足 → 选 VxWorks_rom 或压缩版。

二、VxWorks:带符号的RAM运行镜像

VxWorks是最“原始”的可执行映像,通常由ELF直接转换而来,保留完整符号表,不附加自引导头,也不做压缩。它的典型用法是:BootROM通过TFTP从主机下载该文件到目标板RAM的指定地址(例如0x00100000),然后跳转到入口地址执行。由于符号表完整,目标机可以通过串口或网络与宿主机上的WindSh、Target Server建立连接,实现函数级断点、变量查看和任务级调试。

它的代价是体积大。一个中等规模的内核,符号表往往占几百KB到数MB。因此VxWorks几乎只用于开发调试阶段,不用于最终产品固化。若产品需要现场调试能力,可考虑VxWorks.st。

三、VxWorks.st:带启动头的自引导镜像

VxWorks.st中的“st”通常理解为“standalone”或“startup”,它在VxWorks基础上增加了一个引导头(boot header),使镜像可以被BootROM直接识别并加载,而不需要额外的下载脚本指定入口地址。引导头中记录了镜像长度、加载地址、入口地址和校验信息。BootROM读取头部后,按其中的参数把镜像搬运到RAM并跳转。

与VxWorks相同,VxWorks.st也保留符号表,因此同样支持在线调试。区别在于它更适合“烧写到Flash后由BootROM自举”的场景:开发阶段把VxWorks.st写入Flash,上电后BootROM自动加载,既保留了调试能力,又省去了每次手动下载的麻烦。它常用于开发后期到小批量试产的过渡阶段。

四、VxWorks_rom:ROM中直接执行的镜像

VxWorks_rom面向无RAM加载阶段的固化场景。它剥离符号表,代码段和只读数据段被链接到ROM/Flash的物理地址上,CPU上电后可以直接从ROM取指执行。但RAM是易失的,.data段和.bss段不能留在ROM中,因此镜像中会包含一段搬运代码:启动时把.data从ROM复制到RAM,并把.bss清零,然后才跳转到C语言入口。

这种镜像的优点是启动路径短、不依赖大容量RAM,适合资源受限的嵌入式设备。缺点是代码在ROM中执行,取指速度受Flash访问速度限制,且无法在线符号调试。它通常用于最终产品固化,尤其是RAM容量较小或启动时间要求苛刻的场合。

五、VxWorks_romCompress:压缩固化镜像

VxWorks_romCompress在VxWorks_rom基础上增加了压缩处理:ROM中存放的是压缩后的镜像体,启动时由一小段解压引导代码把压缩数据解压到RAM中,再从RAM执行。它同样不含符号表。

压缩带来的直接收益是Flash占用显著降低,典型压缩比在2:1到3:1之间,具体取决于代码中字符串和常量的比例。代价是启动时需要额外的解压时间,且解压过程需要一块RAM缓冲区。因此它适合Flash容量紧张、但对启动时间不极端敏感的产品,例如批量出货的工业控制器、网络设备等。

六、四类镜像的对比与选型

镜像类型 符号表 压缩 运行位置 典型用途
VxWorks 有 无 RAM 开发调试、网络下载
VxWorks.st 有 无 RAM(自引导) 开发后期、试产固化
VxWorks_rom 无 无 ROM执行 + RAM数据 最终产品固化、小RAM
VxWorks_romCompress 无 有 解压后RAM执行 Flash紧张的量产产品
选型口诀:要调试选带符号(VxWorks / VxWorks.st),要固化选无符号(VxWorks_rom / VxWorks_romCompress);Flash够用选未压缩,Flash紧张选压缩;需要BootROM自举选.st或_rom系列,手动下载选VxWorks。

七、构建配置中的关键参数

在config.h或工程配置中,以下宏直接影响生成哪种镜像:

/* 是否包含符号表 */
#define INCLUDE_SYM_TBL          /* 定义则生成带符号镜像 */

/* 镜像运行位置 */
#define ROM_BASE_ADRS    0xFE000000   /* ROM/Flash 基地址 */
#define ROM_TEXT_ADRS    0xFE001000   /* 代码段在ROM中的起始地址 */
#define RAM_LOW_ADRS     0x00100000   /* RAM 低端地址,用于.data搬运 */
#define RAM_HIGH_ADRS    0x00200000   /* RAM 高端地址,用于解压缓冲 */

/* 压缩选项 */
#define INCLUDE_COMPRESSOR       /* 启用压缩,生成 romCompress 镜像 */

构建时,make会根据这些宏选择对应的转换规则。例如定义了INCLUDE_COMPRESSOR且未定义INCLUDE_SYM_TBL,则输出VxWorks_romCompress;若两者都定义,则输出带符号的压缩镜像(较少使用,因为符号表压缩收益低且调试时解压开销大)。

注意:镜像类型必须与BootROM的加载方式匹配。若BootROM期望带引导头的镜像,却烧写了裸VxWorks,会出现“加载后跑飞”或“入口地址错误”;反之,若BootROM按固定地址加载,却烧写了VxWorks.st,则引导头会被当作代码执行,导致启动异常。烧写前务必确认BootROM的加载约定。

掌握这四类镜像的组成与差异后,就能根据产品阶段(开发/试产/量产)、存储资源(RAM/Flash容量)和调试需求(是否需要符号),快速确定应该构建和烧写哪一种镜像,并为后续的启动链配置打下基础。