掌桥专利:专业的专利平台
掌桥专利
首页

一种基于微内核操作系统的ELF加载方法

文献发布时间:2024-04-18 19:58:30


一种基于微内核操作系统的ELF加载方法

技术领域

本发明涉及计算机技术领域,特别是涉及一种基于微内核操作系统的ELF加载方法。

背景技术

可执行与可链接格式(Executable andLinkable Format,ELF)文件,是一种常见的二进制文件格式,用于存储可执行程序、共享库和内核模块等,最初是由UNIX系统实验室(UNIX System Laboratories,USL)开发并发布的,作为应用程序二进制接口(ApplicationBinary Interface,ABI)的一部分。ELF文件格式主要包含三种类型,可重定位文件(Relocatable File):包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据;可执行文件(Executable File):包含适合于执行的一个程序,此文件规定了如何创建一个程序的进程映像;共享目标文件(Shared ObjectFile):包含可在两种上下文中链接的代码和数据。

ELF加载过程主要分为以下关键步骤:

(1)内核空间准备:在加载ELF文件之前,内核会为进程分配内核空间。这包括为进程创建地址空间、设置内核栈以及其他必要的内核数据结构等。

(2)ELF文件解析:内核会读取ELF文件的头部信息,包括程序头表(ProgramHeaderTable)和节头表(Section HeaderTable),来了解ELF文件的布局和各节的属性。

(3)内存空间分配:根据ELF文件的需求,内核会为进程分配适当的内存空间。它将根据程序头表中的段信息,如代码段(Text Segment)、数据段(Data Segment)、堆(Heap)和栈(Stack)等,来确定这些段在内存中的位置和大小。

(4)段加载:内核将根据程序头表的指示,将ELF文件中的各个段加载到相应的内存地址。这包括将代码段加载到可执行内存区域、将数据段加载到合适的内存位置,并为堆和栈分配相应的内存空间。

(5)符号解析和重定位:在ELF文件的加载过程中,还会进行符号解析和重定位。这涉及到将代码段中的符号引用与实际的函数或变量地址进行关联,并进行必要的地址修正,以确保程序在正确的内存位置执行。

(6)入口点设置等:在加载完ELF文件的各个段后,内核会根据ELF文件的入口点(Entry Point)信息设置程序的起始执行地址。这将引导进程从指定的入口点开始执行代码。

整个ELF加载过程完成后,系统将控制权交给加载的ELF文件,从而启动相应的进程,该进程就可以开始执行其包含的代码和数据,完成相应的操作。由于ELF格式的广泛使用和工具支持,大多数嵌入式操作系统都会选择使用ELF作为默认的可执行文件格式,并提供相应的加载器或运行时环境来支持ELF文件的加载和执行,所以目前部分嵌入式操作系统都已经实现了ELF加载功能。

小型实时操作系统内核(FreeRTOS)的ELF加载将可执行文件加载到内存并执行,其加载过程包括:加载器初始化:加载器初始化为加载和执行的ELF文件做准备,包括初始化内存、寄存器等;ELF文件解析:加载器解析ELF文件的头部,以获取有关程序的基本信息,如程序入口地址、段的大小、段的位置等;内存分配:根据ELF文件指定的段大小和位置,加载器分配足够的内存空间来容纳程序的代码段、数据段和其他相关段;代码和数据复制:加载器将ELF文件中的代码段、数据段等复制到相应的内存地址,以执行其他必要的初始化操作;符号重定位:在ELF文件中,符号表描述了不同符号的地址信息,加载器通过符号表对程序进行符号重定位,即将符号的引用地址改为实际的内存地址;程序入口跳转:加载器将控制权转移到程序的入口地址,开始执行程序。

MINIX、GNU Hurd、Fiasco.OC、Genode等操作系统对于ELF的加载功能实现,虽然细节上会有略微的差异,但大致实现步骤都与标准的加载过程相似,通常包括如下步骤:ELF文件解析:加载器读取ELF文件头的信息,包括入口点地址、代码段和数据段的大小等;分配虚拟内存:加载器为可执行文件分配一块虚拟内存空间,以用于加载代码段和数据段:从ELF文件加载段:加载器根据ELF文件中的段表信息,将需要的程序段加载到先前分配的虚拟内存空间中,代码段将被加载到可执行代码区域,数据段将被加载到适当的数据区域;重定位处理:如果ELF文件包含重定位信息,加载器将执行重定位操作,根据重定位表中的符号信息,将相对地址转换为实际的内存地址,以正确定位各个部分;初始化和启动:加载器完成加载和重定位后,将初始化代码段的全局变量和静态变量,然后加载器设置适当的上下文环境,并将控制权传递给可执行文件的入口点,从而启动可执行程序的执行。

FreeRTOS操作系统是一个基于宏内核设计的实时操作系统,系统在实现ELF加载功能时,ELF解析过程会占用较大运存,造成资源的巨大浪费,同时在基于ARM Cortex-M系列硬件平台开发运行时,因硬件平台本身的资源受限,FreeRTOS在实现ELF加载功能时,不仅消耗了硬件的资源,而且还极大的降低了系统的性能,这样的设计思想与本发明针对的基于ARM Cortex-M系列微内核操作系统是不同的,不利于资源的合理利用、优化处理以及系统性能的提升。

MINIX、GNU Hurd、Fiasco.OC、Genode等微内核操作系统虽然对ELF实现支持,但同样面临资源的消耗,同时在针对ARM Cortex-M系列的硬件平台时,官方未提供任何实用性的ELF加载功能,当应用于ARM Cortex-M系列的硬件平台时,这些微内核操作系统就无法实现相应的功能以及需求了。

发明内容

本发明的目的是提供一种基于微内核操作系统的ELF加载方法,节省了加载ELF文件利用的空间资源。

为实现上述目的,本发明提供了如下方案:

一种基于微内核操作系统的ELF加载方法,包括:

获取ELF加载任务线程上ELF文件的文件描述符;

从所述文件描述符中读取ELF文件头;

对所述ELF文件头进行检查,并当所述ELF文件头通过检查后,从所述ELF文件头中读取各段表信息和各节表信息;

根据所述段表信息和所述节表信息,获取代码段在ELF文件中的位置和大小,以及数据段在ELF文件中位置和大小;

根据代码段的大小确定需要的闪存的空间大小和代码段存放到所述闪存的起始地址;将代码段需要闪存的空间大小和代码段存放到所述闪存的起始地址存放到第一结构体;

根据数据段的大小确定需要的静态随机存储器的空间大小和数据段存放到静态随机存储器的起始地址;将数据段需要静态随机存储器的空间大小和数据段存放到静态随机存储器的起始地址存放到第二结构体;

根据数据段在ELF文件中位置和大小,申请动态内存读取数据段;

根据ELF文件中动态段的信息对读取的数据段包含的数据对象的地址进行重定位;

将重定位后的数据段,根据所述第二结构体存储的信息拷贝到静态随机存储器;

根据所述第一结构体存储的信息,将所述代码段拷贝到闪存;

设置所述ELF文件加载后的应用程序入口。

可选地,所述ELF文件头通过检查的条件包括:e_type为ET_DYN。

可选地,将重定位后的数据段,根据所述第二结构体存储的信息拷贝到静态随机存储器之后,还包括:

释放申请的各个段表的动态内存。

可选地,释放申请的各个段表的动态内存之后,还包括:

指定全局偏移量表的位置,将所述全局偏移量表作为参数传递到应用程序线程。

可选地,设置所述ELF文件加载后的应用程序入口之后,还包括:

在全局的链表中记录已经加载的ELF文件。

可选地,设置所述ELF文件加载后的应用程序入口之后,还包括:

将已经加载的ELF文件对应的应用程序的相关解析数据存入闪存;所述相关解析数据包括符号表、重定位信息、节表、段表、动态链接信息和应用程序的版本信息。

可选地,根据所述第一结构体存储的信息,将所述代码段拷贝到闪存,具体包括:

根据所述第一结构体存储的信息,将所述代码段分段拷贝到闪存。

可选地,获取elf_loader任务线程上ELF文件的文件描述符之前,还包括:

创建用于解析ELF文件的elf_loader任务线程。

根据本发明提供的具体实施例,本发明公开了以下技术效果:

本发明从ELF文件头中根据各段表所占空间大小申请动态内存读取各段表信息,根据各节表所占空间大小申请动态内存读取各节表信息,获取代码段在ELF文件中的位置和大小,以及数据段在ELF文件中位置和大小,将代码段需要闪存的空间大小和代码段存放到所述闪存的起始地址存放到第一结构体,将数据段需要静态随机存储器的空间大小和数据段存放到静态随机存储器的起始地址存放到第二结构体,在加载ELF文件时,根据第一结构体和第二结构体申请内存,降低了不必要段的内存占用,节省了加载ELF文件利用的空间资源。

附图说明

为了更清楚地说明本发明实施例或现有技术中的技术方案,下面将对实施例中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本发明的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动性的前提下,还可以根据这些附图获得其他的附图。

图1为本发明实施例提供的一种基于微内核操作系统的ELF加载方法流程示意图;

图2为本发明实施例提供的一种基于微内核操作系统的ELF加载方法详细流程示意图。

具体实施方式

下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。

本发明的目的是提供一种基于微内核操作系统的ELF加载方法,节省了加载ELF文件利用的空间资源。

为使本发明的上述目的、特征和优点能够更加明显易懂,下面结合附图和具体实施方式对本发明作进一步详细的说明。

对于ELF的加载及优化而言,根据标准的ELF加载过程在ARM Cortex-M系列硬件平台上的自研微内核操作系统中实现ELF加载功能,结合硬件平台以及现有技术存在的部分缺陷,实现ELF加载功能的进一步优化。本发明主要应用场景为基于ARM Cortex-M系列的微内核操作系统,在实现相应硬件平台的ELF加载功能的同时,极大限度的提升硬件资源的利用率与相应系统的性能。

基于Cortex-M系列的ELF加载实现原理如下。

ELF文件分类:可执行文件、可重定向文件、共享库(共享目标文件)。

1)可执行文件包含了代码和数据,是可以直接运行的程序,但是此文件必须在链接时指定程序运行的地址,因为文件中的全局变量、函数指针等都需要引用绝对地址。由于这一步是在文件编译阶段并不知道运行平台的内存分布情况,去获取平台内存使用情况是很麻烦的,而且由于多任务的运行,导致内存使用情况是动态变化的,并且没有MMU虚拟内存技术,显然这种形式的ELF文件不可取。

2)可重定向文件包含了部分代码和数据,是不可以独立运行的,这些文件并没有被链接,也就是每个函数是独立的,不能实现应用程序设计的功能,只能作为链接过程的中间文件。

3)共享库文件包含了全部的代码和数据,此类文件会被编译为地址无关码,地址无关码在链接时不用指定运行地址,那么链接时就不会做重定位,重定位可以放在加载过程中。由于共享库被编译为地址无关码,那么符号引用就并未做重定位,在加载过程中需要根据ELF中的信息做重定位。C语言常见对变量和函数的操作涉及在ELF程序中重定位情况分为直接符号引用和间接符号引用,直接符号引用包括函数调用、变量与常量的访问,间接符号引用是指通过指针完成符号引用。

对于调用全局函数,不是直接跳转过去,而是先跳转到目标函数对应的plt条目,plt条目实际是几条指令组成的一小段代码,它会从got表的一个条目里取出目标函数的地址,然后跳转到这个地址,这个got条目被.rel.plt重定位表的一个条目记为重定位入口,类型为R_ARM_JUMP_SLOT,重定位计算的方式为共享目标对象的加载地址加上目标函数符号的相对地址;对于静态函数,由于调用者和被调用函数在编译时能够确定他们之间的相对地址,因此不需要进行重定位,直接bl指令相对跳转就能实现调用以及正常的函数返回。

对于访问全局变量,也是从got表的一个条目里获取变量运行时的地址,这个got表条目会被.rel.dyn重定位表的一个条目标记为重定位入口,重定位类型为R_ARM_GLOB_DAT,重定位计算方式为共享目标的加载地址加上全局变量符号值。静态变量在链接时已经完成相对地址的重定位,因此在加载时无需重定位。对于只读的常量,重定位过程同可读写的变量一样,只是常量不是放在数据段,而是存放在代码段的.rodata节。对于未初始化的全局变量,其重定位过程同已初始化的全局变量一样。

函数指针涉及的重定位过程相对复杂一些。全局函数指针只想全局函数,涉及两次重定位,第一次重定位的类型为R_ARM_GLOB_DAT,由于全局函数指针实质上就是全局变量,因此第一次就是对数据的重定位,重定位入口为got表条目;第二次重定位类型为R_ARM_ABS32,函数指针存放的是被指向函数的地址,因此第二次是对该函数进行重定位,重定位的入口为全局函数指针的地址。对于静态函数指针指向全局函数,由于静态函数指针实质上就是静态变量,无需重定位,所以只有一次对被指向函数的重定位,类型R_ARM_ABS32,重定位入口为静态函数指针的地址。对于局部函数指针指向全局函数的情况,由于编译链接时不确定被指向函数运行时地址,不能直接将函数地址保存在栈上,所以编译器和链接器为这种情况分配了一条got表条目用于运行时保存函数地址,情况有点类似访问全局变量,所以重定位类型为R_ARM_GLOB_DAT,重定位入口为该got表条目的地址,重定位计算的方式为共享目标对象的加载地址加上被指向函数符号的指。全局函数指针指向静态函数时也需要两次重定位,第一次是对全局函数指针的重定位,类型为R_ARM_GLOB_DAT,重定位入口为got表条目;由于动态符号表不会保存静态函数的信息,所以第二次重定位类型为R_ARM_RELATIVE,重定位入口为全局函数指针的地址,对于这种重定位类型,连接器会在重定位入口上保存被指向静态函数在连接时确定的地址,因此重定位计算的方法为共享目标对象的加载地址加上保存在重定位入口的值。静态函数指针指向静态函数只需要一次重定位,类型为R_ARM_RELATIVE,重定位入口为静态函数指针的地址。对于局部函数指针指向的静态函数,无需重定位,因为涉及使用局部指针的代码指令与被指向的静态函数的相对位置固定,所以在运行时根据pc指针可以计算出目标函数的地址。对于静态局部函数指针的情况,与静态函数指针的一致。使用指针间接访问变量和常量与函数指针情况相似不再详述。

由于Cortex-M系列微处理器不支持虚拟内存技术,运行在此平台上的多任务操作系统中所有的任务都直接使用的物理地址,同时此平台内存较小,程序运行时能动态申请的内存就被可分配的实际内存限制,结合ELF文件实现原理可得出共享库是最符合Cortex-M系列微处理器应用的,本发明即基于此实现ELF的加载功能及优化处理。

如图1和图2所示,本实施例提供的一种基于微内核操作系统的ELF加载方法,包括如下步骤。

步骤101:获取ELF加载任务线程上ELF文件的文件描述符。

步骤101之前,还包括:

微内核操作系统创建用于解析ELF文件的ELF加载(elf_loader)任务线程,创建elf_loader任务线程的过程会为线程分配栈,c语言函数的参数及函数体内部定义的局部变量保存在栈上,设定此线程的优先级,以保证ELF的正常解析。

其中,微内核操作系统具体是指ARM Cortex-M系列微内核操作系统。

步骤102:从所述文件描述符中读取ELF文件头。

其中,步骤102具体包括:

通过网络或串口等方式,将ELF文件传输到文件系统(ARM Cortex-M系列的微内核操作系统中的文件管理模块)里,在已创建elf_loader任务线程的基础上,打开ELF文件,获取文件描述符。

通过获取的文件描述符读取文件头。在32位平台上,ELF文件的前52个字节是ELF文件头,ELF文件头保存了ELF魔数、版本、体系结构、其它数据结构寻址信息等。

步骤103:对所述ELF文件头进行检查,并当所述ELF文件头通过检查后,从所述ELF文件头中根据各段表所占空间大小申请动态内存读取各段表信息,根据各节表所占空间大小申请动态内存读取各节表信息。

所述段表信息包括段表在所述ELF文件中的位置和段表的大小,所述节表信息包括节表在所述ELF文件中的位置和节表的大小;所述ELF文件包括多个段,一个段包括多个节,所述段表用于存储各段所在位置和大小,所述节表于存储各节所在位置和大小。具体段和节的数量取决于ELF文件的结构和内容,段和节的数量根据不同的编译器、链接器和程序的特定需求而有所变化。

其中,所述ELF文件头通过检查的条件包括:e_type为ET_DYN。更具体的,基于获取的52个字节文件头,其中前4个字节是魔数,用字符匹配EI_MAG0为0x7f、EI_MAG1为E、EI_MAG2为L、EI_MAG3为F四个字符为魔数;紧跟着是EI_CLASS为ELFCLASS32值为1,含义是32位平台;EI_DATA为ELFDATA2LSB值为1,取决于运行平台是大端还是小端,此处应该是高位在前,指代小端;EI_VERSION为EV_CURRENT值为1;e_type必须为ET_DYN,因为本发明实现原理是基于对共享库文件的加载,ET_DYN指代共享库文件;e_machine为EM_RAM指代运行在RAM架构的处理器;e_version为EV_CURRENT值为1;e_ehsize为ELF头部的大小,为固定大小sizeof(Elf32_ehdr);e_shentsize为节区头部表格的表项大小,为固定大小sizeof(Elf32_Shdr);e_shnum为节区表格的表项数目必须大于等于1;e_phentsize为程序头部表格的表项大小,为固定大小sizeof(Elf32_Phdr);e_phnum为程序头部表格的表项数目必须大于等一1;以上各个字段检查必须匹配后可进行后续的进一步实现。

进行相关信息检查最重要的原因是使用的是地址无关的共享目标对象,e_type必须是ET_DYN,必须是共享目标文件。如果ELF文件头信息正确,进行后续处理流程,否则释放资源退出线程。

从加载的角度讲,ELF文件由一个个段组成,因此段表是加载ELF程序所必须的。根据ELF文件头中e_phoff得到段表在文件中的位置,根据e_phentsize和e_phnum计算出段表的大小,然后申请对应e_phentsize*e_phnum的动态内存(动态内存指操作系统的堆空间,用于应用程序临时申请的内存空间,后续所提相同)将各个段表从文件中读取存入其中;链接过程所需典型的节表有.dynsym、.dynstr、.rel.dyn、.rel.plt、.plt,根据ELF文件头中e_shoff得到节表在文件中的位置,根据e_shentsize和e_shnum计算出节表的大小,申请对应e_shentsize*e_shnum动态内存将各个节表从文件中读取存入其中,在内存资源少的平台适用,分段的读取解析,以往的技术直接申请大块内存,跟ELF文件的大小一样,这样会造成内存资源少的平台不适用的弊端。

其中,e_phentsize字段表示每个段表项的大小,它指定了每个段表项所占用的字节数。加载器可以根据这个字段的值来确定每个段表项的大小;e_phnum字段表示段表中包含的段表项的数量。加载器可以根据这个字段的值来确定段表的条目数量;计算段表的大小,将每个段表项的大小与段表的条目数量相乘即可得到段表的大小。即段表的大小=每个段表项的大小×段表的条目数量,需要注意的是,实际段表大小应根据相应的实际情况而计算,计算节表大小与之类似。

步骤104:根据读取的所述段表信息和所述节表信息,获取代码段在ELF文件中的位置和大小,以及数据段在ELF文件中位置和大小。

其中,步骤104是指解析必要的段,必要的段包括数据段和代码段。

步骤105:根据代码段的大小确定需要的闪存的空间大小和代码段存放到所述闪存的起始地址;将代码段需要闪存的空间大小和代码段存放到所述闪存的起始地址存放到第一结构体。

步骤106:根据数据段的大小确定需要的静态随机存储器的空间大小和数据段存放到静态随机存储器的起始地址;将数据段需要静态随机存储器的空间大小和数据段存放到静态随机存储器的起始地址存放到第二结构体。

第一结构体和第二结构体均为全局的结构体。

其中,步骤104-步骤106,根据前面读入的段表信息,分别获取代码段(.text)和数据段(.data)在文件中的偏移,并存进全局的结构中。以往的技术:如果一个段的类型是PT_LOAD,那么就会被加载到内存中,有无用的节占用内存资源。

本发明中,一个段由若干个节组成,例如代码包含:.hash、.dynsym、.dynstr、.rel.plt、.rel.dyn、.text、.plt、.rodata、.ARM.exidx、.data.rel.ro、.data、.got、.dynamic、.bss节等,但是其中有的节是在链接过程中使用如:.dynsym、.dynstr、.rel.plt、.rel.dyn、.plt节,那么在运行过程中就无需存在,后续会在恰当的阶段释放内存资源;实际有的节在链接和运行过程都并未使用如:.hash、.ARM.exidx、.data.rel.ro、.dynamic节,就不用申请相应的内存。运行时需要的节有:.text、.rodata、.data、.got、.bss节,闪存(Flash)存放代码段以及只读数据段。

根据.text、.rodata节计算出需要的Flash的大小和存放在Flash的起始地址,并存放在一个全局的结构(第一结构体)中;SRAM存放数据段以及全局偏移量表,根据.data、.got节计算出需要的SRAM的大小和存放在SRAM的起始地址,并存放在一个全局的结构(第二结构体)中。

其中根据.text和.rodata节的信息计算出所需的Flash大小包括:查找.text和.rodata节的节头表项:遍历节头表(Section HeaderTable)中的每个节头表项(SectionHeaderEntry)直到找到与.text和.rodata节对应的节头表项;获取.text节的大小:找到.text节的节头表项后,可以从节头表项中获取.text节的大小字段。这个大小表示了.text节所占用的字节数;获取.rodata节的大小:同样地,找到.rodata节的节头表项后,从节头表项中获取.rodata节的大小字段,表示了.rodata节所占用的字节数;计算Flash的大小:将.text节和.rodata节的大小相加,即可得到所需的Flash大小。这个结果表示了这两个节总共需要的Flash存储空间大小,计算所需的静态随机存储器(Static RandomAccessMemory,SRAM)与之类似。

计算出需要的Flash大小和存放在Flash的起始地址,并将它们存放在一个全局的结构中(SRAM实现与之相同),可以定义一个包含这两个字段的结构体。以下是一个示例:

在这个示例中,FlashLayout结构体包含了两个字段:flashSize和flashStartAddress。flashSize是表示所需的Flash大小的字段,以字节为单位;flashStartAddress是表示存放在Flash的起始地址的字段,通常以字节为单位。

当计算出.text和.rodata节的大小以及它们在Flash中的存放位置后,可以将这些信息存储到FlashLayout结构体的实例中。例如:

FlashLayout flashLayout;

flashLayout.flashSize=4096;

flashLayout.flashStartAddress=0x08000000;

上述实例中假设.text节的大小为4096字节,存放在Flash的起始地址为0x08000000。

这样,flashLayout结构体就包含了计算出的Flash大小和存放在Flash的起始地址的信息(可供后续阶段使用),可以在程序的其他部分使用该结构体来访问和操作这些字段的值。通过使用全局的结构体,可以将计算结果以一种结构化的方式存储,并且方便地在程序的不同部分进行访问和传递。这样,在需要使用Flash大小和起始地址的其他代码段中,只需引用和操作该结构体即可。

静态随机存储器通常用来存储程序的数据段、栈以及其他需要在运行时读写的数据。根据数据段(Data Segment)的概念,通常包括.data节和.bss节。其中,.data节存储已初始化的全局和静态变量,而.bss节存储未初始化的全局和静态变量。因此,SRAM存放的是数据段,即.data节的内容。全局偏移量表(Global OffsetTable,GOT)是一个数据结构,用于存储共享目标文件中全局符号(例如函数、变量)的地址。在链接和运行时,程序可以通过访问全局偏移量表来获取这些全局符号的地址。全局偏移量表在SRAM中存储,以便动态链接器和程序可以查找和更新它们的地址。

步骤107:根据数据段在ELF文件中位置和大小,申请动态内存读取数据段。

其中,步骤107中,将数据段在ELF文件中偏移(位置)和大小,作为读取数据段的起始地址和大小。数据段中包括全局偏移量表,即.got表。

步骤108:根据ELF文件中动态段的信息对读取的数据段包含的数据对象的地址进行重定位。

数据段包含程序在运行时所需的全局变量、静态变量以及其他数据对象。这些数据对象的地址可能在链接时无法确定,因此需要进行重定位,将其正确地放置在内存中。

根据动态段的信息可以寻址到重定位表的信息(此处的表指的是动态链接器在加载和重定位过程中使用的数据结构),DT_REL类型的动态段条目记录了.rel.dyn重定位表的地址,DT_RELSZ类型动态段条目记录了.rel.dyn的大小,DT_JMPREL类型的动态段条目记录了.rel.plt重定位表的地址,DT_PLTRELSZ记录了.rel.plt的大小。根据这些信息及动态符号表等信息进而可以确定重定位信息。其中.rel.dyn是用于数据重定位,.rel.plt用于代码重定位。

步骤109:将重定位后的数据段,根据所述第二结构体存储的信息拷贝到静态随机存储器。

其中,步骤109具体包括:根据前面计算好的数据段在SRAM上的地址拷贝数据段到SRAM。其中计算好的数据段在SRAM上的地址指的是链接器在生成可执行文件时对数据段进行的重定位计算(重定位计算是将程序中的符号引用与实际地址进行关联的过程,确保程序可以正确地访问和调用其他模块中定义的符号)。具体来说,链接器会将数据段中的全局变量、静态变量以及其他数据对象的地址确定为相对地址(相对于数据段的起始位置)。这些相对地址在生成可执行文件时被计算并保存在可执行文件的相应位置。

步骤109之后,还包括:

释放申请的各个段表的动态内存。

指定.got表的位置,将.got表作为参数用于传递到应用程序线程(ELF文件加载后的应用程序入口),以保证应用程序能正确访问变量正常运行。其中.got表在ELF文件加载过程中位于可执行文件的数据段中,其位置由链接器预留并在加载过程中以保证应用程序能正确访问变量正常运行。其中.got表在ELF加载过程中位于可执行文件的数据段中,其位置由链接器预留并在加载过程中填充。.got表会存到R9寄存器,同时存到每个线程的tcb线程控制块中,使得应用程序创建的每个线程都能正常的访问.got表,去链接对应的变量。

步骤110:根据所述第一结构体存储的信息,将所述代码段拷贝到闪存。

由于代码段相对较大,放在这一步拷贝代码段,是在前面占用的动态内存已经释放;同时特定设计了代码段是分段拷贝,每次分段申请的动态空间是限定的。

步骤111:设置所述ELF文件加载后的应用程序入口。

其中,步骤111中设置所述ELF文件加载后的应用程序入口,以便后续创建线程拉起程序。

步骤111之后,还包括:在全局的链表中记录已经加载的ELF文件,,以便下次直接拉起应用程序,无需再次解析安装。

将已经加载的ELF文件对应的应用程序的相关解析数据存入闪存,以便掉电重启后无需再次解析安装。

所述相关解析数据包括符号表、重定位信息、节表、段表、动态链接信息和应用程序的版本信息。

创建程序线程:创建ELF应用程序线程,设置堆栈,设置线程优先级,设置.got表。

退出elf_loader线程:退出elf_loader加载线程,释放申请的动态内存、互斥锁、内核资源等。

本发明基于ARM Cortex-M系列微内核操作系统的ELF加载实现,对资源较小的Cortex-M系列硬件平台,合理设计并实现ELF加载功能,使开发或用户人员能够在微内核系统中灵活的添加、替换或更新应用程序模块,而无需重新编译整个系统,增加了微内核系统的灵活性和可定制性,同时基于ELF功能的实现,还增强了微内核系统的可靠性与维护性。

本发明ELF功能的实现对于相应的微内核操作系统与硬件平台,可实现进一步的扩展与可移植性。在ELF加载功能实现的基础上进行功能的进一步优化处理,实现基于ARMCortex-M系列硬件平台空间资源的最大限度节省与利用。

本说明书中各个实施例采用递进的方式描述,每个实施例重点说明的都是与其他实施例的不同之处,各个实施例之间相同相似部分互相参见即可。

本文中应用了具体个例对本发明的原理及实施方式进行了阐述,以上实施例的说明只是用于帮助理解本发明的方法及其核心思想;同时,对于本领域的一般技术人员,依据本发明的思想,在具体实施方式及应用范围上均会有改变之处。综上所述,本说明书内容不应理解为对本发明的限制。

相关技术
  • 一种基于elf文件实现嵌入式动态APP加载的方法
  • 一种基于可重定位ELF文件的软件快速加载方法
技术分类

06120116500155