ucos在s3c2410上运行过程整体剖析之基础知识--ADS编译、链接器
扫描二维码
随时随地手机看文章
我在学习嵌入式操作系统UCOS时,有很大的迷茫之处,在于我不知道我用的工具到底帮我干了些神马工作。下面就说一下我当时的疑问:
1:编译器和链接器干了些神马?我现在也还没能力知道它是怎么干的这些工作。以后慢慢来呗。但当时我连它干了神马都不清楚。
2:它输入的是源程序,那他输出的是什么?有格式吗?是什么样子那?
重重疑问。
ADS编译器的目的是怎么把高级语言编程能在ARM平台上直接运行的东东。
而我们的目的是看看他干了些神马,让我们了解一下它以及他链接出来的东东是什么样子。对嵌入式整个工程开发做了哪些贡献,这样我们就能更好的使用它了。是不是。
关于ARM嵌入式开发的要点和步骤请参考基于ARM的嵌入式系统程序开发要点.pdf,这里不做详细介绍。
UCOS运行的硬件环境是ARM芯片我们已经在芯片知识章节介绍了,那UCOS 绝大多数代码是用C语言写的,那C语言怎么变成在ARM芯片上运行的代码也是一个问题,因为我们要讲解的是UCOS在具体平台上的具体运行效果。
先说一下编译、链接后ARM程序的组成:
ARM程序的组成
此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别。
一个ARM程序包含3部分:RO,RW和ZI
RO是程序中的指令和常量
RW是程序中的已初始化变量
ZI是程序中的未初始化的变量
由以上3点说明可以理解为:
RO就是readonly,
RW就是read/write,即已初始化的变量
ZI就是zero,程序员未初始化的变量,一般默认初始化为0
(2)
ARM映像文件的组成
所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。
Image文件包含了RO和RW数据。
之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
Q:为什么Image中必须包含RO和RW?
A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。
(3)
ARM程序的执行过程
从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。
实际上,ROM中的指令至少应该有这样的功能:
1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中
在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。
也就是说经过编译器编译出来的可执行程序在内存中有两种状态,一种是刚装载到内存时的状态,即按照你写的函数调用的顺序组织成的连续的二进制代码。另一种是程序运行时的状态。但一般程序真正执行时要把我们写的程序分为代码段、数据段<包括已经初始化的变量和没有初始化的变量>。你想代码段放到内存之后,什么也不用提前做,只等着被取出执行就行。但数据段就不一样了,你想一想,数据段要有本身的属性的(初始化为具体数值或者0),那这些属性必须在程序没有执行前赋给这些变量。怎么赋予它们这些属性那,一般是由编译器产生一些专门负责这些工作的代码来完成。现在大家理解为什么说编译器编译出来的可执行程序在内存中有两种状态了吧。一个是LOAD时的状态,一个是运行时的状态。
我们现在知道了ADS编译出来的程序的样子了,以及编译好的代码要想真正运行还需要做的工作。但问题又出现了,我们怎么利用ADS这个工具使其产生我们所需要的代码的样子以及怎样让他变成真正运行时的样子那?
编译器把源文件编译成ELF的目标文件,然后经连接器最终生成.bin 文件,这种文件可以用于直接烧录到flash中。也即去除了ELF那些格式。
你可以通过简单地配置进行设置编译出的代码的装载地址和运行地址。你也可以用分散加载文件来实现比较复杂的内存映射。有关编译器编译出的代码的装载和运行地址的相关概念请参考:ARM开发工具ADS原理与应用的第十章。