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源派生出的结构关系与加载路径。
二、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紧张的量产产品 |
七、构建配置中的关键参数
在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;若两者都定义,则输出带符号的压缩镜像(较少使用,因为符号表压缩收益低且调试时解压开销大)。
VxWorks,会出现“加载后跑飞”或“入口地址错误”;反之,若BootROM按固定地址加载,却烧写了VxWorks.st,则引导头会被当作代码执行,导致启动异常。烧写前务必确认BootROM的加载约定。
掌握这四类镜像的组成与差异后,就能根据产品阶段(开发/试产/量产)、存储资源(RAM/Flash容量)和调试需求(是否需要符号),快速确定应该构建和烧写哪一种镜像,并为后续的启动链配置打下基础。