CCS 的链接器
一 CCS链接器的作用和过程
汇编器已经将源文件(.asm)顺序地按段的定义(SPC)转换成机器语言目标文件(.obj文件),即COFF文件, 连接器的主要任务是根据连接命令或连接命令文件(.cmd)将一个或多个 COFF目标文件连接起来,生成存储器映象文件(.map)和可执行的输出 文件(.out文件),即COFF目标模块。 链接过程为:
(1)将各个目标文件合并起来,将各个文件的各个段配置到目标系统的存储器中
(2)对各个符号和段进行重定位,并给它们指定一个最终的地址
(3)解决输入文件之间未定义的外部引用 。
二 链接命令文件的写法
coff(公共目标文件格式,Common object file format)文件格式是基于块(section)的概念建立的,即程序被分解成各种块的组合体:如文本块、数据块等。 具有一下特点:
(1)便于实现模块化程序设计
(2)为管理代码块和目标系统存储器提供更强有力和更加灵活的方法
(3)程序员设计时只需基于代码块和数据块等概念进行,不需关注每条命令或每个数据的具体目标地址。至于它们的最终将处于存储器的哪个位置,将由链接器来安排
(4)为程序编写和移植提供了很大的方便
1 section
Section目标文件中最小单位称为块。一个块就是最终在存储器映象中占据连续空间的一段代码或数据。所有的section按照是否自定义可以分为:
(1)Coff默认的section (2)自定义的section ,按照是否初始化可以分为:(1)初始化的section(2)未初始化的section 。C语言和汇编中可能有些不同。
汇编器中默认的section有:
section | 作用 | 通常位置 |
.text |
通常包含可执行代码 |
RAM或者EPROM |
.data |
通常包含已初始化数据 |
ROM或者EPROM |
.bss |
通常用来为未初始化变量保留 |
RAM |
汇编中自定义模块可以通过.sect 创建具可重定位地址的命名块 和.usect创立未初始化块。
C语言的section可以区分如下:
section | 作用 |
.text |
可代码和常数 |
.cinit |
变量初值表 |
.switch | 用于大型switch语句的跳转表 |
.const |
常量和字符串 |
.bss | 全局变量和静态变量 |
.system | 全局堆(用于存储器的分配) |
.stack | 堆栈 |
.far | 以far声明的全局和静态变量 |
.cio | 用于stdio函数 |
.ebss | 长调用的.bss(超过了64K地址限制) |
.esysmem | 长调用的.sysmem(超过了64K地址限制) |
econst | 长.const(可定位到任何地方) |
当然,C语言中可以自定义段
2.CMD
链接器有两种定位快的办法,一种是采用默认的分配算法,汇编中的过程如下:
(1)假定存储器的起始地址为0
(2)假定有2^32字的存储器可以用来分配
(3)将.text分配到起始地址为0的程序存储器中
(4)将.data分配到紧接着.text的程序存储器中
(5)将.bss分配到紧接着.data的程序存储器中
(6)分配自定义的section。
连接器也可以通过链接命令文件来完成,CMD文件由三部分组成:
(1) 输入输出定义;
这一部分,可以通过ccs的“Build Option........”菜单设置。主要包含以下几个部分:
具体的指令有:
-a 产生绝对地址(不可重新定位)的可执行模块,若没有指定-a或-r,默认情况为-a
-r 产生可重新定位不可执行的模块
-ar 产生可重新定位可执行的模块
-b 连接器将不合并任何由于多个文件而可能存在的重复符号表项,此项选择的效果是使连接器运行较快,但其代价是输出的COFF文件较大
-c 使用由TMS320C54x C/C++编译器的ROM自动初始化模型所定义的连接约定
-cr使用由C编译器的RAM自动初始化模型所定义的连接约定
-e global_symbol 定义全局符号为输出模块的指定主入口点
-f fill value为输出段中空洞设定默认的填充值, fill value为16位的常数
-h 使所有的全局符号为静态变量
-g global_symbol保持指定的global_symbol为全局符号,而不管是否使用了-h选项
-help , -? 显示所有可利用的连接命令行选项
-head size为C语言的动态存储器分配设置堆栈大小,以字为单位,并定义指定的堆栈大小的全局符号,size有默认值为1k字
-i dir 改变库搜索方法为在搜索默认的位置前先搜索dir ,该项必须在-l(L)选项之前出现
-l filename 指定一个存档库文件为连接器的输入 , filename为存档库文件名,该选项必须在-i 选项之后出现,目录或文件名必须遵守操作系统的规定
-m filename 产生一个存储器(地址)映射文件,输出名为filename.map , 该文件列出了输入和输出段(包括空洞)的地址
-o filename 指定可执行输出模块的文件名(filename) , 默认为a.out , 目录或文件名必须遵守操作系统的规定
-q 请求静态运行(quiet run) ,即压缩旗标(banner)必须是在命令行的第一个选项
-s 从输出模块中去掉符号表信息和行号
-stack size 设置C系统堆栈,大小以字为单位,并定义指定堆栈大小的全局符号,默认的size为1k
-u symbol 将不能分辩的外部符号放入输出模块的符号表
-vn 指定产生的COFF文件格式n , n=0、1或2,默认为COFF2
-w 当出现没有定义的输出段时,发出警告
-x 迫使重读库,以分辩后面的引用
MEMORY: 定义目标系统的存储器映象,可以给它们命名,规定起始地址和长度
用法:MEMORY { 存储器空间名:o = 十六进制存储器起始地址 l = 十六进制存储器长度 }
例如:
MEMORY { L2RAM: o = 0x10800000 l = 0x00020000 DDR2: o = 0x80000000 l = 0x10000000 }
(3) SECTION命令。
SECTIONS:指定怎样组合各输入块以及将各输出块存放在存储器 的哪个位置
用法:
sections { 段名1 > 存储器空间名1 段名2 > 存储器空间名2 . . . }
例子:
SECTIONS { .bss > L2RAM .cinit > L2RAM .cio > L2RAM .const > L2RAM .data > L2RAM .far > L2RAM .stack > L2RAM .switch > L2RAM .sysmem > L2RAM .text > L2RAM .ddr2 > DDR2 }
CMD中也可以自定义section,用法如下:
#pragma DATA_SECTION(函数名或全局变量名,"用户自定义在数据空间的段名");
#pragma CODE_SECTION(函数名或全局变量名,"用户自定义在程序空间的段名");
具体用法如下:
sections { 段名1 > 存储器空间名1 段名2 > 存储器空间名2 }
可以参开网址:CMD