ADS下C语言的入口方式和ROM镜像文件的生成
这部分介绍下ADS下如何生成可以运行的ROM镜像文件,我们知道当程序下载到flash中运行的时候,对于RW、ZI数据就存在着两个环境,一个load环境,一个是exec环境,有时候由于速度的需要RO数据也要重新加载,那么对RO数据也是有两个环境。编译器产生ROM镜像文件时候,这三块数据的存放依次为RO、RW、ZI,并且地址空间时连续的。但是到了运行的时候,RW数据必须被拷贝到SDRAM(SRAM)中以支持读写,这就是我们所谓的运行环境。那么就要有一段代码去完成这个任务,在本章中我们介绍如何生成这段代码。
玩过2410的朋友都知道2410初始化代码中有一段搬运RW和ZI初始化的代码,没错,它确实能够在一定程度上完成上面所说的任务,只要我们在生成二进制可执行代码的时候在编译器链接项的地方填写正确的RO&RW地址,(比如RO = 0, RW = 0x30000000), 那么将程序下到 NOR flash的零地址并从nor flash启动,启动代码会将RW&ZI数据弄到0x30000000,程序就能跑起来了。
但是各位有没有想过,怎么把RO代码弄到SDRAM中(有时候这是必须的,比方后面我将提到用nor flash的bootloader烧写nor flash)?如果直接设RO=0x30000000,那么这段代码下载到0地址肯定跑不起来,除非是ROPI,这个要求就高了。这里我们有必要从介绍ADS中规定的C语言入口开始,ADS中从初始化汇编代码跳到main函数有两种方式,main和__main:
1,在__main入口的模式下,汇编代码的指令为 b __main, 编译器在跳转到main之前还要作一系列的工作,这其中就包括对运行环境的初始化,在<ADS COMPILE GUIDE>中提到: copies nonroot(RO&RW) execution regions from load addr to exec addr, and Zeros ZI region. 借助编译器,我们就可以定义更为复杂的运行环境,这里要用到scatter文件(.scf),比如我们要的目标运行环境是:将启动代码以外的所有代码都 拷贝到SDRAM的初始地址中运行,比且把RW段设在0x30800000,那么对应的scf文件如下:
FLASH 0x0 0x200000
{
EXEC1 0x0 0x200000
{
2410init.o(Init, +First)
__main.o(+RO) ; copy code
* (Region$$Table) ; RO/RW addresses to copy
* (ZISection$$Table) ; ZI addresses to zero
}
EXEC2 0x30000000 0x00800000
{
*(+RO)
}
SDRAM 0x30800000 0x00800000
{
*(+RW,+ZI)
}
}
;Sections named Region$$Table and ZISection$$Table which contain the addresses of the code/data to be copied.
当然,在这种模式下,有些入口函数必须自己重定义,比如__user_initial_stackheap,具体参见ADS文档。
2, main入口模式即简单的跳转,这里起始不用“main”这个名字也无所谓。那么编译器不会作任何的初始化,所有运行环境的建立都要靠 我们自己,这就是大家看到的那段搬运代码存在的理由。但是它实现一些简单的运行环境是可取的,如果用scf定义的复杂环境,虽然我 相信是可以做到的,但是可能会比较麻烦。我还没深究。
另外,这里提一下semihost,因为我们在看ADS的东西的时候经常出现这个词,我也一直受其困扰。这里我简单说一下自己的见解,semihost 仅仅是一种调试手段,它的机理就是利用MULTI_IDE等工具捕捉目标环境运行过程中产生的值为0x123456的SWI中断,然后向上位机的ADS 软件发送对应的调试信息。对于我们最后的应用代码来说,都是nonsemihost类型的。如果我们在调试中使用semihost,那么只要在最后重定义 ADS中的一些使用到的库函数(比如fputc),代码就可以从semihost向nonsemihost的类型转变。不过到目前为止,我还没体会到semihost的威力。