概述
如果从事 ti DSP 处理器开发,CMD 文件一定是不可忽略的重要文件。当然,CMD 文件也并不是 DSP 处理器的专利,开发 TI ARM(不运行 HLOS 高阶操作系统),MCU 等处理器也都会遇到 CMD 文件。本文就以 C6000 DSP CMD 文件为例,给大家说说 CMD 文件的那些事。首先,需要知道 CMD 文件到底是什么文件?CMD 即 Linker Command Files 命令链接文件。CMD 发挥作用的阶段是在我们程序开发的链接阶段。即下图 Linker 阶段。
需要注意的是英文 Linker Command Files 中的 Files 是复数,也就是说在一个 DSP 项目中,CMD 文件可以不止一个。不论是否运行实时操作系统,都可以有多个 CMD 文件,但是不同的 CMD 文件中的内容不能有冲突,否则编译工具链会报链接错误!既然 CMD 文件在链接阶段发挥作用,那么就需要知道编译工具链在链接阶段究竟做了些什么?◆分配段到目标系统可配置内存区域◆重新定位符号和段并指派最终地址◆解析不同文件中未定义的外部引用◆分配段到特定的内存区域◆合并目标文件段◆定义或重定义链接时全局符号说了这么多,简而言之链接过程主要是一些对符号和程序段内存分配的操作。而 CMD 文件最主要的功能就是内存分配。 使用 CMD 文件CMD 文件结构: CMD 文件主要有三部分内容
- 1、链接选项
- 可以在 CMD 文件修改链接选项,比如
- -heap 0x1000
- -stack 0x1000
- 这两个参数是指定堆和栈的大小,这里需要注意的是堆栈,虽然一般都放在一起描述,但它们可不是一回事。
- -l ../../../Library/Codec/h264hpvdec_ti.le66
- 还可以链接静态库(-l 小写英文字母 L),这里使用的是相对路径。
复制代码
- 2、MEMORY 指令 - 目标处理器内存区域描述
- 这一部分主要是描述目标处理器中内存区域,只要是可访问的内存区域都可以在这里描述,当然需要用到的内存空间要描述,不用到的可以不用描述。需要注意的是,这个内存描述仅在 CMD 文件中有效,不会影响其它文件,也不可以在其它文件中引用。
- 语法
- MEMORY
- {
- name 1 [( attr )] : origin = expression , length = expression [, fill = constant]
- .
- .
- name n [( attr )] : origin = expression , length = expression [, fill = constant]
- }
- name 命名一段内存区域,长度 1 - 64 个字符,可以使用 A - Z,a - z,$,.以及 _。
- attr 为这段内存区域指定 1 - 4 个属性。可选参数。属性限制对于段的分配。如果,不指定该参数即代表不限制该内存段属性。有效的属性有
- R 内存区域可读
- W 内存区域可写
- X 内存区域包含可执行代码
- I 内存区域可被初始化
- origin 指定内存区域起始地址,也可以写作 origin,org 或 o。地址以字节为单位的 32 位常量表达式,可以是十六进制、十进制或者八进制。
- length 指定内存区域长度,也可以写作 length,len 或 l。可以是十六进制、十进制或者八进制。
- fill 使用指定字符填充内存区域,也可以写作 fill 或 f。可选参数。填充字符为一个整数常量,可以是十六进制、十进制或者八进制。 fill 用于填充一段不用来分配段的内存区域。
- 地址操作可以使用的表达式,表达式的规则与标准 C 语言一致。
- 单目运算符 - ~ !
- 双目运算符 * / % + - <<>> == = <<= >>= & | && ||
- 其它 START SIZE END 这三个关键字分别用于获取引用内存区域的起始地址、大小及结束地址。
-
- 使用表达式描述地址的范例。
- /********************************************************/
- /* 范例 */
- /********************************************************/
- file1.obj file2.obj /* 输入文件 */
- --output_file=prog.out /* 选项 */
- #define ORIGIN 0x00000000
- #define BUFFER 0x00000200
- #define CACHE 0x0001000
-
- MEMORY
- {
- FAST_MEM (RX): origin = ORIGIN + CACHE length = 0x00001000 + BUFFER
- SLOW_MEM (RW): origin = end(FAST_MEM) length = 0x00001800 - size(FAST_MEM)
- EXT_MEM (RX): origin = 0x10000000 length = size(FAST_MEM) - CACHE
- }
- 1、SECTIONS 指令 - 分配程序段到内存
- 描述输入段如何合并到输出段;
- 定义可执行文件中的输出段;
- 指定输出段放置到的内存区域;
- 允许重命名输出段。
-
- SECTIONS
- {
- name : [property [, property] [, property] . . . ]
- name : [property [, property] [, property] . . . ]
- name : [property [, property] [, property] . . . ]
- }
-
- 加载分配 定义段被加载到的内存区域
- 语法: load = 区域或
- 区域或
- > 区域
- 运行分配 定义段运行的内存区域
- 语法: run = 区域 或
- run > 区域
- 输入段定义用于组成输出段的输入段(目标文件)
- 语法: { 输入段 }
- 段类型 定义特定段标志
- 语法: type = COPY 或
- type = DSECT 或
- type = NOLOAD
- 填充值 定义用来填充未初始化区域(Hole)值
- 语法: fill = 值 或
- 名称: [属性= 值]
-
- SECTIONS 指令范例
- /**************************************************/
- /* 范例 */
- /**************************************************/
- file1.obj file2.obj /* 输入文件 */
- --output_file=prog.out /* 选项 */
- SECTIONS
- {
- .text: load = EXT_MEM, run = 0x00000800
- .const: load = FAST_MEM
- .bss: load = SLOW_MEM
- .vectors: load = 0x00000000
- {
- t1.obj(.intvec1)
- t2.obj(.intvec2)
- endvec = .;
- }
- .data:alpha:
- .data:beta:
- }
-
- 结合前面的范例,最终的内存分配如下图所示
复制代码
此外,有部分段由编译器及程序设计语言(C++ / C / 汇编)定义,当然开发人员也可以自行定义段。
编译工具创建的已初始化的程序段(EABI)
编译工具创建的未初始化的程序段(COFF ABI 及 EABI)
自行定义段名称不能跟这些名称冲突。
转自创龙微信公众号
3
|
|
|
|