LDRPC, [PC, OFFSET_TO_LPOOL]
LPOOLDCD main
可见,虽然LDR是把基于PC的一个存储单元LPOOL的内容加载到PC中,但该存储单元中保存的却是链接时所决定的main函数入口的绝对地址,所以main函数实际所在的段不是位置无关。
② 位置无关的常量访问。在应用程序中,经常要读写相关寄存器以完成必要的硬件初始化。为增强程序的可读性,利用EQU伪指令对一些常量进行赋值,但在访问过程中,必须实现位置无关性。下面以PXA270的GPIO初始化介绍位置无关的常量访问方法。
程序入口为_start,即复位异常,所有其他异常向量都使用相对跳转指令B来实现,以保证位置无关特性。在完成基本的硬件初始化后,利用链接脚本传递过来__boot_start和__boot_end的参数,将Bootloader映像整个拷贝到指定的SDRAM空间,并清零.bss段,初始化堆栈后,程序将main函数入口的绝对地址赋给PC,进而跳转到SDRAM中继续运行。程序在跳转到main函数之前,所有的代码都在ROM中运行,因而必须要保证代码的位置无关性,所以在调用初始化GPIO、存储系统和堆栈等子程序时,都使用相对跳转指令来完成。 使用位置无关设计Bootloader程序有如下优点:
① 简化设计,方便实现系统的快速引导。位置无关代码可以避免在引导时进行地址映射,并方便地跳转到SDRAM中实现快速引导。
② 实现复位处理智能化。由于位置无关代码可以被加载到任意地址空间运行,因此其运行时的当前地址与链接时所指派的地址并不一定相同。利用这一特性,可以在复位处理程序中使处理器进入SVC模式并关闭中断后加入如下代码,便可根据当前运行时的地址进行不同的复位处理:
上述代码中的ADR指令读取的_start标号地址由指令的执行地址决定。若是从SDRAM中的Bootloader启动,则上述比较结果相等,程序直接跳转到clear_bss标号地址处执行,这样可以避免存储系统的重新初始化和Bootloader的拷贝过程;若是上电或硬件复位,程序从ROM启动,则上述比较结果不等,程序便进行包括系统初始化和Bootloader拷贝等过程的全面复位处理操作。
③ 便于调试。Bootloader的调试通常也是一个繁琐的过程,使用位置无关代码,则可以将映像文件加载到SDRAM中进行调试,这既能真实地反映程序从ROM中进行系统引导的情况,又可以避免频繁烧写程序存储器。 3 结论
本文所介绍的基于位置无关的程序设计是通过基于PC或基址寄存器的符号引用规范来实现的。这种方法在实际系统开发中应用广泛,既能用于引导程序的设计,也可用于一般的应用程序或嵌入式共享库的开发。而在Bootloader的设计中引入位置无关代码,可以使程序结构更为简单清晰,并能避免地址重映射并从SDRAM进行快速系统引导;引用位置无关的设计方法使Bootloader的复位处理功能更为灵活,还使得在SDRAM中和在ROM中进行程序调试具有相同的效果。 参考文献
[1] 杜春雷. ARM体系结构与编程[M]. 北京:清华大学出版社,2003.
[2] 陈文智. 嵌入式系统开发原理与实践[M]. 北京:清华大学出版社,2005.
[3] ARM Limited. ARM Architecture Reference Manual. 2nd ed,2000.
[4] ARM Limited. ADS Developer Guide. Release 1.2,200111.
[5] ARM Limited. ADS Assembler Guide. Release 1.2,200111.
[6] Red Hat Inc. Using ld, the GNU linker. Version 2.14.