一种手机嵌入式系统中动态加载的方法
技术领域
本发明涉及无线通信技术领域,尤其涉及一种增强手机嵌入式系统加载功能的方法。
背景技术
传统的手机嵌入式系统(例如ARM、Linux、uClinux、WinCE、PalmOS、Symbian、eCos、uCOS-II、VxWorks、pSOS、Nucleus、ThreadX、Rtems、QNX、INTEGRITY、OSE、C Executive等系统)都是把程序全部烧入只读存储器(ROM)中,手机在FLASH上加载并运行程序。动态加载功能目前只有智能机操作系统(SYMBIAN、WINDOWS MOBILE)才有,采用实时操作系统的手机平台(例如基于MIPS的RTOS平台)不具备动态加载功能。因此,程序的使用受到FLASH大小的限制,并且若程序员需要更新程序,则只能全部更新,而无法做到部分地更新。
要解决上述问题,目前市面上有一种系统:高通的BREW,但是BREW必须配套高通专门的芯片才能使用。
因此,手机开发业界存在一种技术需求:提供一种手机嵌入式系统中动态加载的方法,使得实时操作系统具备动态加载功能。
发明内容
本发明的目的是提供一种手机嵌入式系统中动态加载的方法,包含如下步骤:
编译应用程序,将应用程序独立编译为一个程序文件,程序文件描述了程序文件所支持的处理器架构及节头表所在的位置;
加载程序文件,通过节头表读出指令及只读数据节、初始化的全局变量节和未初始化的全局变量节在程序文件中的位置,将指令及只读数据节、初始化的全局变量节和未初始化的全局变量节加载到内存的适当位置即实现程序的动态加载;
初始化运行环境,将堆栈和堆的配置参数传递给应用程序,重构_rt_stackheap_init()函数;
参数替换,当执行初始化运行环境步骤至函数_rt_init_stackheap()时,用加载器传入的参数替换_rt_init_stackheap()函数;
继续初始化,用加载器传入的参数继续初始化程序运行环境步骤;
生成目标代码,将应用程序生成为ROPI(READ ONLYPOSITION INDEPENDENT,只读位置无关)和RWPI(READ WRITE POSITION INDEPENDENT,读写位置无关)代码模式;
调用宿主函数,首先将宿主函数名称传递给符号表函数,符号表函数将宿主函数的地址返回给应用程序,应用程序将宿主函数的入口参数填写完毕后跳转至函数地址,即完成调用宿主函数的过程;
中断C运行时库的退出部分流程,完成程序文件的动态加载过程。
在本发明的其中一个实施例中,加载应用程序的步骤包含如下步骤:
读入程序文件头部的加载信息;
根据加载信息计算程序加载后所需要使用的内存容量;
根据加载信息将程序加载到内存中;
初始化传递给程序的参数列表,将参数列表复制到程序的参数区;
跳转到程序的入口地址。
本发明的优点是:使手机的实时操作系统具有动态加载功能。
附图说明
下面结合附图,通过对本发明的具体实施方式的详细描述,将使本发明的技术方案及其他有益效果显而易见。
图1为本发明手机嵌入式系统中动态加载的方法流程图;
图2为本发明中加载程序文件的工作流程图。
具体实施方式
为了更进一步了解本发明的特征,请参阅以下有关本发明的详细说明与附图,然而所附图式仅提供参考与说明之用,并非用来对本发明的保护范围加以限制。
如图1所示,为本发明方法的流程图。首先101程序开始执行,然后执行102编译应用程序;编译应用程序:将应用程序独立编译为一个程序文件,主流的程序文件格式有ELF(Executable and LinkableFormat)、a.out(UNIXv5标准)、PE(Portable Executable,Microsoft Windows专用格式)。ARM公司提供的ADS所生成的程序文件格式是ELF,ELF相对于平面结构的a.out格式有着更好的扩展性和平台无关性,相对于Windows专用的PE格式,ELF能够更好地支持异构平台。ELF文件的格式如下表所示:其文件头部的ELF header描述了程序文件所支持的处理器架构及节头表(Section header table)所在的位置。
ELF header |
Program header table |
.text |
.rodate |
.data |
Section header table |
之后执行103,由加载器加载程序文件;加载程序文件时,首先为只读段和读写段分配内存,这部分
内存用于保存代码与数据,加载次序为ER_RO(代码及只读数据)、ER_RW(初始化的全局变量)、ER_ZI(未初始化的全局变量)。程序和中间件使用同一个堆栈,中间件分配一块连续内存作为程序的堆,程序的动态内存分配在堆中实现。
通过节头表读出ER_RO(指令及只读数据节)、ER_RW(初始化的全局变量)和ER_ZI(未初始化的全局变量)在程序文件中的位置,将这些节加载到内存的适当位置即可实现程序文件的动态加载。
程序文件加载后的内存映像如图3所示。
ER_RO被加载到上表中的只读段,ER_RW和ER_ZI被依次加载到上表中的读写段,堆和堆栈的分配由加载器负责。
之后执行步骤104,初始化运行环境。程序加载完毕后,初始化运行环境。初始化运行环境包括堆和堆栈的初始化。堆用于保存动态分配的内存,堆栈在函数调用时用于保存临时变量及保护现场。
根据ARM C RUNTIME(C语言运行时库,这是C语言链接到程序中的一组系统代码)规范,堆及堆栈初始化必须重构_rt_stackheap_init()函数。这个函数的默认以ARM的SEMI HOSTING实现,由于大多数手机开发平台都没有实现SEMI HOSTING,因此需要重构该函数。
由于堆栈和堆是由VRE的加载器实现的,而_rt_stackheap_init()函数在被加载程序中,所以加载器必须把堆栈和堆的配置参数通过某种方式传递给应用程序。参数至少包括堆和堆栈配置、宿主函数符号表函数。传递方式有两种,一是通过堆栈传递,二是通过共享内存传送。由于ADS在不同编译参数下会链接不同的目标库,而堆栈的分配和目标库有关,因此用堆栈传递会降低系统可移植性,所以VRE采用共享内存传递参数方式。
被传递的参数被存放在堆以下的128字节中,应用程序中的_rt_stackheap_init()函数通过这块内存获取加载器传递过来的参数。获得参数后,_rt_stackheap_init()按照ARM的约定把堆和堆栈的配置参数通过R0~R3寄存器返回给C RUNTIME(C语言运行时库,这是C语言链接到程序中的一组系统代码),这样即重构了_rt_stackheap_init(),也即修改了该函数的默认实现,其重构后,按照新的流程执行。之后生成目标代码;为了支持程序的动态加载,应用程序必须以ROPI(READ ONLYPOSITION INDEPENDENT,只读位置无关)和RWPI(READ WRITE POSITION INDEPENDENT,读写位置无关)(Read Only/Read WritePosition Independent)模式生成。ADS的ARMCC编译器通过加入-apcs/ROPI(Read Only PositionIndependent,只读位置无关)/RWPI(Read Write Position Independent,读写位置无关)参数编译代码,ARMLINK加-ROPI(Read Only Position Independent,只读位置无关)-RWPI(Read Write PositionIndependent,读写位置无关)参数生成程序文件。
支持ROPI(READ ONLY POSITION INDEPENDENT,只读位置无关)和RWPI(READ WRITEPOSITION INDEPENDENT,读写位置无关)代码采用了基于PC和SB(STATIC BASE,静态基址寄存器)寄存器寻址方式,即对函数和只读数据的寻址基于PC,而全局变量的寻址基于SB(STATIC BASE,静态基址寄存器)寄存器。这种寻址方式是ARM ATPCS规定的,因此采用本方法完全符合ARM的标准,不需要另外开发编译器和连接器。
当执行初始化至函数_rt_init_stackheap()时,执行步骤105,用加载器传入的参数替换_rt_init_stackheap()函数;然后执行步骤106,用加载器传入的参数继续初始化程序运行环境。
之后,执行步骤107,执行程序的main()函数,也即调用宿主函数。宿主函数的地址通过符号表函数返回,当应用程序要调用一个系统函数时,首先把函数名称传递给符号表函数,符号表函数把这个函数的地址返回给应用程序,应用程序把系统函数的入口参数填写完毕后跳转至函数地址,即完成调用过程。程序文件执行完毕后,即执行步骤108,中断C运行时库的退出部分流程。因为如果让C运行时库继续执行下去,程序文件就会被强制退出,这样加载就失败了,所以必须执行步骤108,将默认的流程中断,才能完成程序文件的加载过程。109结束。
如图2所示,为本发明加载程序文件的工作流程图。首先执行201步骤,读入程序文件头部的加载信息;然后执行步骤202,根据加载信息计算程序文件加载后所需要使用的内存容量;步骤203根据加载信息将程序文件加载到内存之中;步骤204初始化传递给程序的参数列表,将列表复制到程序的参数区;205跳转到程序的入口地址。