Embedded-Club https://bbs.21ic.com/?538166 [收藏] [复制] [RSS] ┃无线┃智能┃环保┃艺术┃

日志

EasyARM2200开发板学习笔记:初级C程序运行环境的建立

已有 1206 次阅读2008-7-21 10:21 |个人分类:Olyaim's 智能|系统分类:ARM| LPC2200, EasyARM2200, 启动代码, ADS1.2, ZI, RO, RW

以下启动代码是从EasyARM2200开发板的例子程序中提取出来的简单启动代码,当然这种启动代码在实际开发中是不太可能用到的,这里只是为了启动过程的理解方便。但就这么简单的几行代码却还是有一些东西让人不太理解,比如|Image$$XX$$Limit||Image$$XX$$Base|,有意思,那就接着分析吧。


 1 启动文件,初始化C程序的运行环境,然后进入C程序代码。


 3         IMPORT    |Image$$RO$$Limit|


 4         IMPORT    |Image$$RW$$Base|


 5         IMPORT    |Image$$ZI$$Base|


 6         IMPORT    |Image$$ZI$$Limit|


 7


 8         IMPORT    Main      声明C程序中的Main()函数


 9


10         AREA      Start,CODE,READONLY   声明代码段Start


11         ENTRY      标识程序入口


12         CODE32     声明32ARM指令    


13            


14 Reset   LDR       SP,=0x40003F00     设置堆栈指针


15


16         初始化C程序的运行环境


17         LDR       R0,=|Image$$RO$$Limit|


18         LDR       R1,=|Image$$RW$$Base|    


19         LDR       R3,=|Image$$ZI$$Base|    


20             


21         CMP       R0,R1


22         BEQ       LOOP1


23 LOOP0   CMP       R1,R3      


24         LDRCC     R2,[R0],#4     


25         STRCC     R2,[R1],#4 


26         BCC       LOOP0


27         


28 LOOP1   LDR       R1,=|Image$$ZI$$Limit| 


29         MOV       R2,#0


30 LOOP2   CMP       R3,R1


31         STRCC     R2,[R3],#4


32         BCC       LOOP2


33         


34         B         Main     跳转到C程序代码Main()函数


35        


36         END


 


ADS1.2的朋友都知道在编译连接一个ARM程序之前要根据开发板的实际存储配置设置连接器的选项,这里我就以EasyARM2200的开发板来配置,因为我使用的是LPC2210处理器,片内无FLASH,片内RAM地址范围初设置为0x40000000~0x40003FFF,大小只有16Kbytes,所以大一点的程序就不能在这里面调试了,当然此开发板片外也配有512KbytesRAM2MbytesFLASH,它们的地址可根据跳线来配置,这里就先不讲解。我们这个程序只在片内RAM中调试就可以了,下面就是DebugDel生成目标的连接器配置:


 



 



 


配置完成后,点击Make后会生成一个编译连接报告,如下:


 



 




     


    结合启动代码、连接器配置、编译连接报告和ADS1.2帮助文档我们隐约可以看出刚才那几个怪怪的 symbol代表什么了:


    |Image$$RO$$Base| 


    表示RO输出段运行时起始地址,也可以说是程序代码存放的起始地址,由-ro-base这个参数       指定,所以|Image$$RO$$Base|=0x40000000


    |Image$$RO$$Limit|


    表示RO输出段运行时存储区域界限,其值可通过|Image$$RO$$Base|+Code sizes+RO Data  sizes计算得出,所以|Image$$RO$$Limit|=0x40000090


    |Image$$RW$$Base|


    表示RW输出段运行时起始地址,记得是运行时的地址,而不一定是加载时的存放地址,因为RW输出段 在加载时可能是在ROM中并紧跟着RO输出段存放的,当程序运行时才复制到RAM起始地址为|Image $$RW$$Base|的区域,由-rw-base这个参数指定,所以|Image$$RW$$Base|=0x40003000;如 果未指定-rw-base,默认紧跟RO输出段,那么|Image$$RW$$Base||Image$$RO$$Limit|


    |Image$$RW$$Limit|


    表示RW输出段运行时存储区域界限,其值可通过|Image$$RW$$Base|+RW Data sizes计算得 出,所以|Image$$RW$$Limit|=0x40003004


    |Image$$ZI$$Base|


    表示ZI输出段运行时起始地址,它是运行时在RAM中生成的,紧跟着RW输出段存放,其值和|Image $$RW$$Limit|一样,所以|Image$$ZI$$Base|=0x400030004


    |Image$$ZI$$Limit|


    表示ZI输出段运行时存储区域界限,其值可通过|Image$$ZI$$Base|+ZI Data sizes计算得 出,所以|Image$$ZI$$Limit|=0x40003008


     


    看出什么没有,原来上面这些都是在运行时域的地址,那从加载时域到运行时域之间我们的处理器还对其烧进去的程序做了什么呢?这就又得回到启动代码中去看,认真分析可以看出LOOP0LOOP1正是引导处理器对其上面这些输出段的操作。下图就是LOOP0LOOP1所做的工作。


     



     


    可以看出这里的RW段完全可以不做复制,因为0x40003000也是在内部RAM中,那怎么让RW段不做复制呢?有两种方法:


    第一种是不定义RW Base0x40003000,这样加载时域和运行时域的RW段在同一个地址且紧接着RO段,生成的ZI段也紧接着RW段,如下图:


     



     


    第二种是使用两个加载时域,定义RO段所在的加载时域的起始地址为0x40000000RW段所在的加载时域的起始地址直接设置为0x40003000,如下图:这样RW段也就可以和RO段分开加载了,运行时就不用重新复制RW段,提高运行效率。


     



     


    不过上面这几种方法都只适用于调试,也就是程序加载时都是放在RAM中才行。如果是最终加载到ROM的程序那就要用到一个加载时域和多个运行时域的方法,这里先不深入,下次再分析,吃饭去了。


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)