微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ADS中RO Base和RW Base的作用

ADS的Setting中有对ARM Linker的设置,其中包括对RO Base和RW Base的设置,这两项设置主要有以下的作用(以S3C2440为例):

1、程序编译完后要烧录到Flash中运行,对于norflash,程序可以在norflash中运行,但运行速度受限制,而且,程序中用到的变量必须放在SDRAM中才能正常使用;而对于Nandflash,程序不能在Nandflash中运行,需要在Bootloader中将Nandflah中的程序拷贝到SDRAM中运行(选择Nandflash启动方式时,cpu自动将Nanflash中的前4k程序复制到stepping stone中运行,stepping stone是ARM自带的SRAM中的一部分,并且,stepping stone会自动映射成0x00地址。所以,此时程序从0x00地址启动时,就能正常运行Nandflash中的程序了。如果选择norflash启动,内部SRAM在地址0x40000000处)。既然涉及到了程序拷贝,就要用到以下几个常量:

|Image$$RO$$Base|  ; Base of ROM code
|Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)
|Image$$RW$$Base|  ; Base of RAM to initialise
|Image$$ZI$$Base|  ; Base of area to zero initialise
|Image$$ZI$$Limit|  ; limit of area to zero initialise

程序编译完后,这些常量的值就确定了。其中|Image$$RO$$Base|就是ADS的ARM Linker中的RO Base,|Image$$RW$$Base| 就是ADS的ARM Linker中的RW Base,|Image$$RO$$Limit|、|Image$$ZI$$Base|和|Image$$ZI$$Limit|是编译器根据RO Base和RW Base自动计算出来的。所以,在将程序由flash拷贝到SDRAM的过程中,要用到RO Base和RW Base。

2、在汇编到代码中,会用到label,如:

ResetEntry

 b ResetHandler

其中ResetEntry和ResetHandler均为label,这些label的地址位置会在编译后确定,常用ldr伪指令实现跳转到某label处,如:

ldr pc,=copy_proc_beg

执行完上条指令后,pc变为RO Base+offset(offset是copy_proc_beg与代码首地址的偏移量)。

一般来说,RO Base的值为0x00,所以感觉不到RO Base在此处的作用,但对于特殊用途,如将RO Base设置为0x10000000的时候,就能感受到RO Base的用途了。

一般而言,一个程序包括只读的代码段和可读写的数据段。在ARM的集成开发环境中,只读的代码段和常量被称作RO段(ReadOnly);可读写的全局变量和静态变量被称作RW段(ReadWrite);RW段中要被初始化为零的变量被称为ZI段(ZeroInit)。对于嵌入式系统而言,程序映象都是存储在Flash存储器等一些非易失性器件中的,而在运行时,程序中的RW段必须重新装载到可读写的RAM中。这就涉及到程序的加载时域和运行时域。简单来说,程序的加载时域就是指程序烧入Flash中的状态,运行时域是指程序执行时的状态。对于比较简单的情况,可以在ADS集成开发环境的ARM LINKER选项中指定RO BASE和RW BASE,告知连接器RO和RW的连接基地址。对于复杂情况,如RO段被分成几部分并映射到存储空间的多个地方时,需要创建一个称为“分布装载描述文件”的文本文件通知连接器把程序的某一部分连接在存储器的某个地址空间。需要指出的是,分布装载描述文件中的定义要按照系统重定向后的存储器分布情况进行。在引导程序完成初始化的任务后,应该把主程序转移到RAM中去运行,以加快系统的运行速度。

       什么是arm的映像文件
arm映像文件其实就是可执行文件包括bin或hex两种格式,可以直接烧到rom里执行。在axd调试过程中,我们调试的是axf文件,其实这也是一种映像文件,它只是在bin文件中加了一个文件头和一些调试信息。映像文件一般由域组成,域最多由三个输出段组成(RO,RW,ZI)组成,输出段又由输入段组成。所谓域,指的就是整个bin映像文件所处在的区域,它又分为加载域和运行域。加载域就是映像文件被静态存放的工作区域,一般来说flash里的 整个bin文件所在的地址空间就是加载域,当然在程序一般都不会放在 flash里执行,一般都会搬到sdram里运行工作,它们在被搬到sdram里工作所处的地址空间就是运行域。我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,经过编译后就变成了bin文件ro段和rw段,还有所谓的zi段,这就是输出段。对于加载域中的输出段,一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。
在运行域中这些输出段并不连续,但rw和zi一定是连着的。zi段和rw段中的数据其实可以是rw属性。 

       | Image$$RO$$Base| |Image$$RO$$Limit| |Image$$RW$$Base| |Image$$ZI$$Base| |Image$$ZI$$Limit|这几个变量是编译器通知的,我们在 makefile文件中可以看到它们的值。它们指示了在运行域中各个输出段所处的地址空间,
| Image$$RO$$Base| 就是ro段在运行域中的起始地址,|Image$$RO$$Limit| 是ro段在运行域中的截止地址,其它依次类推。我们可以在linker的output中指定,在 simple模式中,ro base对应的就是| Image$$RO$$Base|,rw base 对应的是|Image$$RW$$Base|,由于rw和zi相连,|Image$$ZI$$Base| 就等于|Image$$RW$$limit|
。其它的值都是编译器自动计算出来的。

   下面是2410启动代码的搬运部分,我给出注释:

BaSEOfROM DCD |Image$$RO$$Base|

TopOfROM DCD |Image$$RO$$Limit|

BaSEOfBSS DCD |Image$$RW$$Base|

BaSEOfZero DCD |Image$$ZI$$Base|

EndOfBSS DCD |Image$$ZI$$Limit|

adr r0,ResetEntry; ResetEntry是复位运行时域的起始地址,在boot nand中一般是0

ldr r2,BaSEOfROM;

cmp r0,r2

ldreq r0,TopOfROM;TopOfROM=0x30001de0,代码段地址的结束

beq InitRam 

ldr r3,TopOfROM

;part 1,通过比较,将ro搬到sdram里,搬到的目的地址从 | Image$$RO$$Base| 开始,到|Image$$RO$$Limit|结束



ldmia r0!,{r4-r7} ;将r0值作为地址处(ResetEntry)连续的4个32位数依次转入r4,r5,r6,r7;同时r0增加

stmia r2!,{r4-r7};将r4,r5,r6,r7的值依次存入|Image$$RO$$Base|地址处;同时r2增加

cmp r2,r3

bcc %B0;

;part 2,搬rw段到sdram,目的地址从|Image$$RW$$Base| 开始,到|Image$$ZI$$Base|结束

sub r2,r2,r3;r2=0 ;上面拷贝时每次拷贝4个双字(32位)大小,但是RO段大小不一定是4的整数倍,所以可能多拷贝了几个双字大小,r2-r3得到多拷贝的个数

sub r0,r0,r2 ;
r0-(r2-r3)可以使r0指向在boot nand中RO的结束地址


InitRam ;carry rw to baSEOfBSS

ldr r2,BaSEOfBSS ;TopOfROM=0x30001de0,baSEOfrw

ldr r3,BaSEOfZero ;BaSEOfZero=0x30001de0

0

cmp r2,r3

ldrcc r1,[r0],#4

strcc r1,[r2],#4

bcc %B0 

;part 3,将sdram zi初始化为0,地址从|Image$$ZI$$Base|到|Image$$ZI$$Limit|

mov r0,#0;init 0

ldr r3,EndOfBSS;EndOfBSS=30001e40



cmp r2,r3

strcc r0,#4

bcc %B1

至此三个输出段组成(【 在 afellow (我在他乡) 的大作中提到: 】
: 首先说一下,我认为我还是看了不少的资料,然后再来问这个问题的,看起来下面
: 我写的很多,其实我只是想把问题描述清楚一点,我认为我已经写的比较详细了,所以应该不会耽误各位大侠多少时间,所以希望能耐心看完,谢谢 !
: 我在各种资料上都看过相关的解释:

 -ro-base address(即设定Image$$RO$$Base--我的理解)  
: 这个选项将包含有RO(Read-Only属性)输出段的加载地址和运行地址设置为address
: ,该地址必须是字对齐的,如果没有指定这个选项,则认的RO基地址值为0x8000。
: -rw-base address  
: 这个选项设置包含RW(Read/Write属性)输出段的域的运行时地址,该地址必须是字
: 对齐的。  
: Image$$RO$$Base is the address of the read-only execution region (usuall
: ycontains code and read-only data).--ro运行时地址
: Image$$RW$$Base is the address of the read-write execution region (usual
: lycontains data).--rw运行时地址
: 所以大致意思,我是知道的,不过在还是在有几个问题想不明白:
    问题1、就是这个设定的Image$$RO$$Base与我们复位时cpu读取第一条指令的  
: 0x0 地址有什么关系?这个“Image$$RO$$Base”到底又设定了那些源代码的运行起始地址?比如在一个Bootloader中,往往包含同时包含汇 编代码和C语言代码两部分,这个“Image$$RO$$Base”只设定了C语言中RO段的运行地址 ?(拷贝RO RW段代码到Image$$RO$$Base
,Image$$RW$$
 
cpu运行地址和你的设定没有关系,如果你的程序上电在Flash中运行,则ro设置成
cpu的复位运行地址(0x00000000),如果是在RAM中运行,就设定为RAM的地址。连接
器会把所有的不需要改变的代码和数据(read only)放到ro基地址,如CODE和数据常
量,象const修饰的数据。而在rw基地址放置变量,包括STACK区。汇编和C,连接器
是不会区分的。
    如果说也设定了汇编中ro部分代码的运行地址,那问题2又怎么解释 ?
    问题2、有人说“请注意,将工程编译为烧入Flash的二进制代码时,需要将链接器重新设置,将调试时程序空间定位地址(RO Base地址)改为0x00000000”,但我明明刚刚编译的Bootloader就将ro base设为了0xf00000,现在我已将其烧写入Flash中测试过,Bootloader运行良好�
这说明你的bootloader是基于相对地址的,也就是说与地址无关,而这也是对bootloader
一个基本要求。一般的bootloader都设计成地址无关的。
    这样一来我到有个奇怪的想法就是,如果我的程序没有C语言代码,岂不是就可以不用管这个ro base的设置?因为从一开机到拷贝ro/rw段前,我所有的汇编代码执行良好。
如果你的汇编代码没有用到绝对地址跳转等,则你说的没错,但是设置一下ro要花很多
时间么?
    问题3、我的vector.S中复位入口“ResetEntry”的部分代码如下,用AXD载入ADS编译的这个.bin文件的时候可以看到,这个 “ResetEntry”标号开始的代码被编译到了.bin文件的最前面,因为我在链接设置里面把reset section放在了img的最前面。我有点不明白就是这个“Reset
        AREA    reset,CODE,READONLY
        ENTRY    
: ;复位和上电启动的入口
: ResetEntry
        b       SYS_RST_HANDLER
        b       UDF_INS_HANDLER
: .........................................
Image$$RO$$Base就是你设定的ro基址,那么连接器会把你的CODE从这个地址开始
放置,也就是ResetEntry会和该地址保持一致,而和cpu的复位运行地址没有关系。
    4、我在AXD调试程序时还发现,调试过程中我可以把ADS生成的.bin文件载入S
: DRAM中任何位置,然后修改pc值执行之,不论你的Image$$RO$$Base,Image$$ROW$$Base设定在什么地方,当然我的这个调 试的程序肯定没有对ro/rw段做任何的拷贝操作。这让我更对RW段运行时地址和Image$$ROW$$Base的关系感到疑惑,因为rw段中不是保存 有程序需要的变量或数据么
这说明你的程序比较小,或者函数调用不复杂,堆栈操作不频繁等。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐