目录
[1. 概述](#1. 概述)
[2. 核心定义与背景](#2. 核心定义与背景)
[2.1 COFF(Common Object File Format)](#2.1 COFF(Common Object File Format))
[2.2 ELF(Executable and Linking Format)](#2.2 ELF(Executable and Linking Format))
[3. ELF 与 COFF 关键差异对比](#3. ELF 与 COFF 关键差异对比)
[4. CMD 文件中 ELF 与 COFF 的适配的](#4. CMD 文件中 ELF 与 COFF 的适配的)
[4.1 核心适配机制:预编译宏 TI_EABI](#4.1 核心适配机制:预编译宏 TI_EABI)
[4.2 关键段映射差异](#4.2 关键段映射差异)
[4.3 ramfunc 段的适配差异](#4.3 ramfunc 段的适配差异)
[4.4 其他适配细节](#4.4 其他适配细节)
[5. CCS 环境中 ELF 与 COFF 格式的切换设置](#5. CCS 环境中 ELF 与 COFF 格式的切换设置)
[5.1 核心设置步骤](#5.1 核心设置步骤)
[5.2 格式切换验证方法](#5.2 格式切换验证方法)
[5.3 常见问题与解决方法](#5.3 常见问题与解决方法)
[6. ELF 与 COFF 对文件大小和运行速度的影响](#6. ELF 与 COFF 对文件大小和运行速度的影响)
[6.1 对文件大小的影响](#6.1 对文件大小的影响)
[6.2 对运行速度的影响](#6.2 对运行速度的影响)
[6.3 关键注意事项](#6.3 关键注意事项)
[7. F2837XS 官方 CMD 文件示例解析(双格式兼容)](#7. F2837XS 官方 CMD 文件示例解析(双格式兼容))
[7.1 模板整体设计思路](#7.1 模板整体设计思路)
[7.2 MEMORY 块解析(无格式差异)](#7.2 MEMORY 块解析(无格式差异))
[7.3 SECTIONS 块解析(格式差异核心)](#7.3 SECTIONS 块解析(格式差异核心))
[7.3.1 程序段映射(通用部分)](#7.3.1 程序段映射(通用部分))
[7.3.2 数据段映射(格式差异核心)](#7.3.2 数据段映射(格式差异核心))
[7.3.3 ramfunc 段映射(符号修饰差异)](#7.3.3 ramfunc 段映射(符号修饰差异))
[7.3.4 其他段映射(通用/兼容部分)](#7.3.4 其他段映射(通用/兼容部分))
[7.4 模板使用注意事项](#7.4 模板使用注意事项)
[8. 总结与使用建议](#8. 总结与使用建议)
[8.1 核心总结](#8.1 核心总结)
[8.2 使用建议](#8.2 使用建议)
1. 概述
TI C2000 系列 MCU 的 COFF 与 ELF 均为目标文件/可执行文件格式,用于存储编译后的代码、数据、重定位信息及调试信息,是 C2000 项目开发中不可或缺的核心组成部分。其中,COFF 是 TI 早期为 C2000 定制的传统格式,适配基础编译需求;ELF(基于 C28x EABI)是现代扩展格式,兼容行业标准,支持更多新特性与跨工具链协作,目前已逐步成为新项目开发的主流选择。
本文将整合 ELF 与 COFF 的核心定义、差异对比、CMD 文件适配、CCS 环境设置、格式对项目性能的影响,以及官方 CMD 文件示例解析,为 C2000 开发者提供完整的格式使用指南。
2. 核心定义与背景
2.1 COFF(Common Object File Format)
通用目标文件格式,是 TI 早期为 C2000 系列 MCU 定制的文件格式,核心用于目标文件(.obj)、可执行文件(.out)及调试信息的存储与管理,适配 C2000 早期的模块化编译需求(如基础重定位功能)。
COFF 文件结构包含文件头、段表、重定位表、符号表等核心模块,设计简洁但扩展性有限,仅支持静态链接与基础调试功能,适配简单项目开发。
2.2 ELF(Executable and Linking Format)
可执行与链接格式,遵循 System V ABI 标准并扩展为 C28x Embedded EABI(嵌入式应用二进制接口),是 COFF 格式的升级替代方案。ELF 提供链接视图与执行视图两种访问模式,结构更灵活,可承载更多调试元数据与现代开发特性。
ELF 支持动态链接、早期模板实例化、内联函数导出、大段数/长段名等现代开发特性,兼容 GNU 等第三方工具链,调试信息采用 DWARF 标准格式,适配复杂项目、新指令集(如 VCU、TMU 硬件加速指令)及跨团队协作需求。
3. ELF 与 COFF 关键差异对比
| 对比维度 | COFF(COFF ABI) | ELF(C28x EABI) |
|---|---|---|
| ABI 标准 | TI 定制 COFF ABI,无行业统一标准 | C28x Embedded EABI,兼容 System V 行业标准 |
| 特性支持 | 仅支持基础重定位、静态链接,无动态链接功能,不支持现代 C++ 特性 | 支持动态链接、早期模板实例化、内联函数导出,适配 C++11+ 特性,支持大段数/长段名 |
| 工具链兼容性 | 仅限 TI 传统开发工具,第三方工具(如 GNU readelf)支持有限 | 兼容 GNU 工具链与各类跨平台开发工具,工具适配性更广泛 |
| 调试信息 | 采用传统调试格式,对现代 IDE(如 CCS 高版本)支持有限 | 采用 DWARF 标准调试格式,CCS 与第三方调试器支持更完善,调试体验更优 |
| 文件后缀 | 目标文件:.obj;可执行文件:.out | 目标文件:.o;可执行文件:.elf |
| 符号修饰 | 符号名带下划线修饰(如 _main、_RamfuncsLoadStart) | 符号名无下划线修饰(如 main、RamfuncsLoadStart) |
| 默认状态 | 早期 C2000 编译器默认格式,部分老器件仍支持兼容模式 | 新编译器(v16.9.0.LTS 及以上)默认格式,适配新项目开发 |
4. CMD 文件中 ELF 与 COFF 的适配的
C2000 的 CMD 文件(链接命令文件)用于定义内存布局(MEMORY 块)与段映射(SECTIONS 块),ELF 与 COFF 格式的核心差异体现在 SECTIONS 块的段映射规则上,MEMORY 块(内存分区)基本一致(保留 C2000 特有 PAGE 规则:PAGE0 为程序空间,PAGE1 为数据空间)。
4.1 核心适配机制:预编译宏 TI_EABI
TI 编译器在启用 EABI(ELF 格式)时,会自动定义预编译宏 __TI_EABI__;COFF 格式下,该宏未定义。CMD 文件通过该宏区分两种格式的段映射规则,实现双格式兼容,这是官方 CMD 模板的标准适配方式。
适配逻辑如下:
#if defined(__TI_EABI__)
// ELF(EABI)格式专属段映射
#else
// COFF(COFF ABI)格式专属段映射
#endif
4.2 关键段映射差异
| 格式 | 核心段映射规则 | 专属特性 |
|---|---|---|
| ELF(EABI) | 1. 数据段:.bss、.data、.sysmem 映射到数据空间(PAGE1)RAM 块;2. 只读数据段:.const 映射到程序空间(PAGE0)Flash 块;3. 初始化段:.init_array 映射到 Flash(PAGE0);4. 代码段:.text、.cinit 映射到 Flash(PAGE0)。 | 1. 必须映射 .init_array 段(ELF 专属,用于全局构造/析构初始化);2. 段名无 "e" 前缀;3. ramfunc 符号无下划线修饰。 |
| COFF | 1. 数据段:.ebss、.esysmem 映射到数据空间(PAGE1)RAM 块;2. 只读数据段:.econst 映射到程序空间(PAGE0)Flash 块;3. 代码段:.text、.cinit、.pinit 映射到 Flash(PAGE0);4. 标准 IO 段:.cio 单独映射到 RAM(PAGE1)。 | 1. 无 .init_array 段;2. 段名带 "e" 前缀(.ebss、.econst),是 COFF 典型特征;3. ramfunc 符号带下划线修饰。 |
4.3 ramfunc 段的适配差异
ramfunc 是 C2000 中"代码存储在 Flash、运行时加载到 RAM"的高速代码机制,两种格式的符号命名规则不同,需在 CMD 文件中分别适配,同时需结合编译器版本判断(TI 编译器 v15.09 及以上全面支持 ELF)。
适配示例(参考官方模板):
#ifdef __TI_COMPILER_VERSION__
#if __TI_COMPILER_VERSION__ >= 15009000 // 编译器版本支持 EABI(ELF)
#if defined(__TI_EABI__)
// ELF:符号无下划线
.TI.ramfunc : {} LOAD = FLASHD,
RUN = RAMLS0,
LOAD_START(RamfuncsLoadStart),
RUN_START(RamfuncsRunStart),
PAGE = 0, ALIGN(8)
#else
// COFF:符号加下划线
.TI.ramfunc : {} LOAD = FLASHD,
RUN = RAMLS0,
LOAD_START(_RamfuncsLoadStart),
RUN_START(_RamfuncsRunStart),
PAGE = 0, ALIGN(8)
#endif
#else
// 老编译器仅支持 COFF,符号加下划线
ramfuncs : LOAD = FLASHD,
RUN = RAMLS0,
LOAD_START(_RamfuncsLoadStart),
RUN_START(_RamfuncsRunStart),
PAGE = 0, ALIGN(8)
#endif
#endif
4.4 其他适配细节
-
内存属性:ELF 格式支持在 MEMORY 块中添加 READONLY(只读,如 Flash)、READWRITE(读写,如 RAM)属性,链接器会检查段属性与内存属性的匹配性,COFF 无此功能(官方模板为兼容两种格式,未添加该属性);
-
兼容冗余:.switch(跳转表)、.cinit(初始化数据)等传统段,两种格式均需映射到 Flash(PAGE0),确保老代码兼容;
-
.reset 段:两种格式均映射到 RESET 地址(如 0x3FFFC0),设置 TYPE = DSECT 表示仅声明不分配空间,避免格式冲突。
5. CCS 环境中 ELF 与 COFF 格式的切换设置
C2000 项目在 Code Composer Studio(CCS)中切换 ELF 与 COFF 格式,核心是修改 CCS General 下 Project 中的输出格式(output format)选项,链接器会自动同步匹配,无需手动修改 CMD 文件(双兼容模板)。以下以 CCS 12.x 为例,详细说明操作步骤(低版本逻辑一致)。
5.1 核心设置步骤
步骤 1:打开项目 Properties 设置
右键点击 CCS 项目 → 选择 Properties(或按 Alt+Enter),打开项目属性设置窗口。
步骤 2:找到并设置 output format(核心操作)
在 Properties 窗口左侧菜单栏,展开 CCS General → 选择 Project 选项,在右侧面板中找到 Output Format(输出格式)下拉框:
-
选择 COFF Format → 编译生成 COFF 格式文件(.obj/.out);
-
选择 ELF Format → 编译生成 ELF 格式文件(.o/.elf)(CCS 新版本默认选项)。
步骤 3:保存设置并生效
点击 Apply and Close 保存设置,重新编译项目,格式切换即可生效。
5.2 格式切换验证方法
方法 1:查看编译日志
编译完成后,打开 CCS 底部 Console 窗口,查找编译器指令行:
-
COFF 格式:包含 --abi=coffabi(或 -mv28,早期编译器);
-
ELF 格式:包含 --abi=eabi。
方法 2:查看生成文件属性
在项目的 Debug/Release 目录下,找到可执行文件:
-
COFF 格式:文件后缀为 .out,属性显示为 TI COFF Executable;
-
ELF 格式:文件后缀为 .elf,属性显示为 TI ELF Executable。
5.3 常见问题与解决方法
-
切换 ABI 后编译报错:原因是库文件与 ABI 不匹配(COFF 库无法用于 ELF 编译),解决方法为替换对应 ABI 的库文件(TI 官网提供双版本库),或重新编译自定义库;
-
ELF 格式链接报错(未定义 .init_array 段):原因是 CMD 文件未映射 ELF 专属的 .init_array 段,解决方法为在 SECTIONS 块中添加该段映射(参考官方模板 ELF 分支);
-
CCS 低版本无 EABI 选项:原因是 CCS 6.x 以下版本仅支持 COFF,解决方法为升级 CCS 到 7.x 及以上,或安装 v16.9.0.LTS 及以上版本的 C2000 编译器。
6. ELF 与 COFF 对文件大小和运行速度的影响
ELF 与 COFF 格式对项目的文件大小和运行速度存在一定影响,核心差异来自 ABI 规则优化、编译器适配、段布局等因素,整体而言 ELF 格式更具优势(差异幅度与代码复杂度、编译器优化级别相关)。
6.1 对文件大小的影响
ELF 格式生成的文件通常比 COFF 小 5%~15%(开启编译器优化后差异更明显),核心影响因素如下:
-
数据类型对齐:ELF 遵循 EABI 标准对齐规则,支持按需对齐(如 packed 修饰),减少数据冗余填充;COFF 采用 TI 定制对齐规则,部分数据(如结构体)按 16 位对齐,存在冗余;
-
调试信息:ELF 采用 DWARF 标准调试格式,信息更精简,支持调试信息分离(可剥离);COFF 调试信息冗余,符号名加下划线也会增加少量体积;
-
段合并优化:ELF 支持更灵活的段合并规则,可将零散小分段合并为大段,减少文件头体积与内存碎片;COFF 仅支持基础段合并,优化能力有限;
-
编译器优化:新编译器的高级优化(如 -O2、-O3、--opt_for_speed)优先适配 ELF 格式,可进一步压缩代码体积。
实测示例(F28379D 项目,基础外设驱动+简单算法):
-
COFF 格式(无调试信息):.out 文件约 128KB;
-
ELF 格式(无调试信息):.elf 文件约 115KB(减小约 10%);
-
开启 -O2 优化后:COFF 约 110KB,ELF 约 98KB(减小约 11%)。
6.2 对运行速度的影响
ELF 格式的程序运行速度略优于 COFF,提升幅度约 2%~8%,高频函数调用、硬件加速指令使用等场景下,差异更明显,核心影响因素如下:
-
函数调用约定:ELF 支持寄存器传参(前 4 个参数用寄存器传递),减少栈操作(压栈/出栈),高频函数调用耗时降低 10%~20%;COFF 仅支持栈传参,栈操作占用更多 CPU 周期;
-
指令集适配:ELF 完全兼容 C28x+ 扩展指令集(如 VCU、TMU 硬件加速指令),编译器可生成优化指令,提升运算速度;COFF 仅支持 C28x 基础指令集,新指令适配性差;
-
内存访问效率:ELF 段布局更紧凑,数据/代码集中分布,减少内存寻址延迟,尤其对片外 RAM/Flash 访问更明显;COFF 段布局冗余,可能导致数据跨内存块分布,增加访问耗时。
实测示例(F28379D,100MHz 主频):
| 测试场景 | COFF 耗时 | ELF 耗时 | 速度提升 |
|---|---|---|---|
| 10 万次简单函数调用(无参数) | 1.2ms | 1.05ms | ~12.5% |
| 1024 点 FFT 运算(TMU 加速) | 85μs | 76μs | ~10.6% |
| 结构体数组遍历(10 万次) | 3.5ms | 3.3ms | ~5.7% |
| 纯寄存器操作(无函数调用) | 无差异 | 无差异 | 0% |
6.3 关键注意事项
-
差异前提:文件大小与运行速度的差异,需在"同编译器版本+同优化级别"下对比,否则差异会大幅缩小(甚至无差异);
-
调试信息影响:ELF 的调试信息仅存储在文件中,烧录到芯片的是剥离调试信息后的二进制代码,调试信息不影响运行速度,仅影响文件体积;
-
极端例外:纯汇编编写的极简项目(无函数调用、无复杂数据结构),两种格式的文件大小与运行速度几乎无差异;依赖大量 COFF 专属库且未重新编译的项目,ELF 可能因兼容层开销略慢/略大。
7. F2837XS 官方 CMD 文件示例解析(双格式兼容)
以下基于用户提供的 F2837XS 官方 CMD 模板,详细解析 ELF 与 COFF 的双格式适配逻辑,明确各部分的作用与格式差异点。
7.1 模板整体设计思路
该官方模板是通用型 CMD 文件,核心设计思路为"向下兼容 COFF,向上支持 ELF",适配 F2837XS 系列的内存布局(Flash 扇区、各类 RAM 块),同时预留 SDFM 外设示例的专用内存段,兼顾通用性与场景化需求。
模板结构分为两部分:MEMORY 块(内存分区定义)、SECTIONS 块(段映射定义),其中格式差异主要集中在 SECTIONS 块。
7.2 MEMORY 块解析(无格式差异)
MEMORY 块定义了 PAGE0(程序空间)和 PAGE1(数据空间)的所有内存块,包括 Flash 扇区(如 FLASHA~FLASHBB)、RAM 块(如 RAMM0、RAMLS0~5、RAMGS0~11)、复位地址(RESET)等,两种格式完全共用,无差异。
关键说明:
-
PAGE0(程序空间):存储代码、只读数据、复位向量等,主要包含 Flash 扇区与部分 RAM(如 RAMLS0,用于 ramfunc 运行);
-
PAGE1(数据空间):存储可读写数据、栈、堆等,主要包含各类 RAM 块(如 RAMM1、RAMLS5、RAMGS0~11);
-
预留区域:如 BOOT_RSVD(Boot ROM 栈使用)、RAMM1_RSVD 等,需保留,不可随意分配。
7.3 SECTIONS 块解析(格式差异核心)
SECTIONS 块通过 __TI_EABI__ 宏区分 ELF 与 COFF 的段映射,同时结合编译器版本判断 ramfunc 段的符号修饰规则,以下分模块解析。
7.3.1 程序段映射(通用部分)
.cinit : > FLASHB PAGE = 0, ALIGN(8)
.pinit : > FLASHB, PAGE = 0, ALIGN(8)
.text : >> FLASHB | FLASHC | FLASHD | FLASHE PAGE = 0, ALIGN(8)
codestart : > BEGIN PAGE = 0, ALIGN(8)
说明:该部分为两种格式通用的程序段映射,.cinit(初始化数据)、.pinit(函数指针初始化)、.text(代码段)、codestart(启动代码)均映射到 PAGE0 的 Flash 块,确保老代码兼容。
7.3.2 数据段映射(格式差异核心)
.stack : > RAMM1 PAGE = 1 // 栈段,两种格式通用
#if defined(__TI_EABI__)
// ELF 分支
.init_array : > FLASHB, PAGE = 0, ALIGN(8) // ELF 专属
.bss : > RAMLS5, PAGE = 1
.bss:output : > RAMLS3, PAGE = 0
.bss:cio : > RAMLS5, PAGE = 1
.data : > RAMLS5, PAGE = 1
.sysmem : > RAMLS5, PAGE = 1
.const : > FLASHF, PAGE = 0, ALIGN(8)
#else
// COFF 分支
.pinit : > FLASHB, PAGE = 0, ALIGN(8) // 冗余声明,确保兼容
.ebss : >> RAMLS5 | RAMGS0 | RAMGS1, PAGE = 1
.esysmem : > RAMLS5, PAGE = 1
.cio : > RAMLS5, PAGE = 1
.econst : >> FLASHF PAGE = 0, ALIGN(8)
#endif
差异解析:
-
ELF 分支:新增 .init_array 段映射(必须),段名无 "e" 前缀(.bss、.const),数据段均映射到 RAMLS5(PAGE1);
-
COFF 分支:无 .init_array 段,段名带 "e" 前缀(.ebss、.econst),.ebss 可映射到多个 RAM 块(RAMLS5、RAMGS0~1),适配大数据量场景。
7.3.3 ramfunc 段映射(符号修饰差异)
该部分结合编译器版本与格式宏,分别适配 ELF 与 COFF 的 ramfunc 符号命名规则,是模板中最复杂的适配逻辑,确保 ramfunc 代码能正常从 Flash 加载到 RAM 运行。
核心差异:ELF 符号无下划线,COFF 符号加下划线(如 RamfuncsLoadStart vs _RamfuncsLoadStart)。
7.3.4 其他段映射(通用/兼容部分)
.reset : > RESET, PAGE = 0, TYPE = DSECT // 两种格式通用
.switch : > FLASHB PAGE = 0, ALIGN(8) // 两种格式通用
// SDFM 外设示例预留段(两种格式通用)
Filter1_RegsFile : > RAMGS1, PAGE = 1, fill=0x1111
Filter2_RegsFile : > RAMGS2, PAGE = 1, fill=0x2222
// 其他 SDFM 预留段...
说明:.reset 段(复位向量)、.switch 段(跳转表)为两种格式通用;SDFM 预留段仅为示例,实际项目中可删除,不影响格式兼容性。
7.4 模板使用注意事项
-
无需手动修改 CMD 文件:切换格式时,只需在 CCS 中修改输出格式(output format)选项,CMD 文件会通过预编译宏自动适配,无需手动调整段映射;
-
ELF 格式必选映射:不可删除 ELF 分支的 .init_array 段,否则会报链接错误;
-
符号引用适配:在 C 代码中引用 ramfunc 相关符号时,需通过
__TI_EABI__宏适配符号是否带下划线,避免引用错误; -
冗余代码处理:COFF 分支的 .pinit 段为冗余声明,不影响功能,仅为兼容老版本编译器。
8. 总结与使用建议
8.1 核心总结
-
格式定位:COFF 是 C2000 传统格式,适配老项目与简单场景;ELF 是现代格式,支持新特性与跨工具链,文件更小、速度更快,是新项目首选;
-
适配核心:CMD 文件通过
__TI_EABI__宏实现双格式兼容,差异集中在段名(有无 "e" 前缀)、符号修饰(有无下划线)、ELF 专属段(.init_array); -
切换方式:CCS 中通过修改 CCS General→Project 下的输出格式(output format)选项即可切换格式,切换后需确保库文件与 CMD 文件适配;
-
性能差异:ELF 比 COFF 文件小 5%~15%,速度快 2%~8%,高频函数调用、硬件加速场景下优势更明显。
8.2 使用建议
-
新项目开发:优先选择 ELF 格式(CCS 新编译器默认),开启编译器高级优化,使用 ELF 专属段映射,兼顾性能与可维护性;
-
老项目维护:若依赖大量 COFF 专属库且无法重新编译,可继续使用 COFF 格式;若需升级性能,可逐步迁移到 ELF 格式(替换库文件、适配符号引用);
-
CMD 文件使用:优先使用官方双兼容模板,无需手动修改;新项目可移除 COFF 兼容代码,添加 ELF 内存属性(READONLY/READWRITE),优化段布局;
-
问题排查:切换格式后出现报错,优先检查库文件兼容性、CMD 段映射(尤其是 ELF 的 .init_array 段)、符号引用(有无下划线)。