从事了这么久的ARM开发,对entry point的含义一知半解,今日再次拿出一本写得还算不错的ARM教材来翻,书中这一段仅仅是把英文手册单纯翻译成中文,并没有讲到真正的实质。不是ARM公司手册写得不详细,而是多数中文教材的编写采用的方式是: english--华文 mapping,但英文手册是有系列组织的suite,而书本往往翻译自系列中的一篇,容易使得读者管中窥豹。 摘要:ARM link的时候-entry ‘行标号’ 选项用于指定程序的入口地址,其实就是ICE把代码load完之后自动跳入的地址,最后的程序中这个工作是由bootloader来完成的,当然bootloader也可以跳到别的入口地址去。几乎所有的成品ARM芯片都有内置的bootloader,因此开发者看到的程序入口点就是entry point。对于FPGA上的ARM系统调试,ARM复位后跳转到一个固化地址,就需要自己写bootloader代码并通过scatter加载到rom中(我们的EAS片上存储器包括rom在内全部用FPGA的ram实现,tape out的时候bootloader代码会被固化到chip的rom中) 1.entry point在编译中的指定 看了make file,entry point的指定是在link的时候用命令行参数的方式告诉编译器的, armlink ... -Entry reset_handler 如果采用RVDS或ADS,工程属性中有entry point选项可供设置,但最终还是作为参数传递给armlink。 这样, 在连接ICE并loadimage之后,ICE会通过JTAG把代码映像搬移到内存中,然后把当前PC指针指向reset_handler,但引出了一个问题:在最终的产品中不存在ICE和JTAG,ARM上电复位后跳向固化的复位地址,如0xFFFF0000,那么由谁来让PC指针指向我们指定的entry point呢?答案是:由bootloader代码来完成,进一步引出2个问题:1,谁来生成bootloader?2,怎么把bootloader定位到硬件复位地址? 2. 自己写bootloader并通过scatter文件将之定位到硬件复位地址。 或许某些开发工具会自动的为我们生成bootloader,这里介绍的是自力更生的方法。 首先介绍bootloader,这里仅实现中断向跳转: AREA Vect, CO ENTRY ;这个entry和本文中的entry point是没有关系的,它表示的是汇编程序代码部分的开始 LDR PC, Reset_Addr LDR PC, Undefined_Addr LDR PC, SWI_Addr LDR PC, Prefetch_Addr LDR PC, Abort_Addr NOP ; Reserved vector LDR PC, IRQ_Addr LDR PC, FIQ_Addr Reset_Addr DCD Reset_Handler Undefined_Addr DCD Undefined_Handler SWI_Addr DCD SWI_Handler Prefetch_Addr DCD Prefetch_Handler Abort_Addr DCD Abort_Handler IRQ_Addr DCD IRQ_Handler FIQ_Addr DCD FIQ_Handler Reset_Handler LDR PC, =0x00000000; 然后是scatter文件: ROM_LOAD 0x00000000 { ROM_EXEC 0x00000000 { * (InRoot$$Sections); 实现搬移scatter的代码,编译器自动生成 *(+RO) ; 除了bootloader的所有代码段放这里 } D-TCM 0x00400000 0x003FFFFF { * (+RW,+ZI);这里放所有的RW段(char ch=4;)和ZI段(char ch; ch会被初始化零)。 } } ROM2 0xFFFF0000 { BOOTLOAD 0xFFFF0000 { bootloader.o(+RO) ;bootloader的程序段放这里 } } scatter也是在link的时候通过参数‘-scatter 文件名’传递的。 3.总结 在以上条件下,比较使用ICE和最终产品中的启动顺序:当使用ICE调试时,ICE读入映像文件,找到其中的scatter信息,通过JTAG把代码段和数据段放到指定的位置,然后把PC设为-entry所指定的标号,这就是为什么当我们loadimage之后看到的是在entry point中指定的行号所在的源代码。当脱离ICE运行时,ARM上电后跳转到硬件复位地址0xFFF0000 (ROM),我们已事先在那里烧入了我们的bootloader,bootloder从外设中读入加载映像文件(如片外nand,I2C,UART等)并放入scatter的加载域中(0x00000000),然后跳转到0x000000,由于我们已在scatter中将InRoot$$Sections定位在那里,所以它被执行,它负责把映像文件从加载域搬移到执行域中,然后跳转到__main,__main是arm编译器自动生成的,它负责清零ZI段和初始化C库,最后__main跳向C代码的入口main() |
上一篇:s3c2410物理地址和虚拟地址空间
下一篇:ARM的存储器映射与存储器重映射
推荐阅读最新更新时间:2024-03-16 15:01