ARM开发各种烧写文件格式说明(ELF、HEX、BIN)

发布者:CreativeMind最新更新时间:2016-08-01 来源: eefocus关键字:ARM开发  烧写文件  格式说明 手机看文章 扫描二维码
随时随地手机看文章
一、ELF


         Executable and linking format(ELF)文件是x86Linux系统下的一种常用目标文件(object file)格式,有三种主要类型:
         (1)适于连接的可重定位文件(relocatable file),可与其它目标文件一起创建可执行文件和共享目标文件。 
         (2)适于执行的可执行文件(executable file),用于提供程序的进程映像,加载的内存执行。 
         (3)共享目标文件(shared object file),连接器可将它与其它可重定位文件和共享目标文件连接成其它的目标文件,动态连接器又可将它与可执行文件和其它共享目标文件结合起来创建一个进程映像。 
ELF文件格式比较复杂。

二、HEX
        
         Intel HEX文件是记录文本行的ASCII文本文件,在Intel HEX文件中,每一行是一个HEX记录,由十六进制数组成的机器码或者数据常量,Intel HEX文件经常被用于将程序或数据传输 
存储到ROM、EPROM,大多数编程器和模拟器使用Intel HEX文件。 
         记录格式 
         一个Intel HEX文件可以包含任意多的十六进制记录,每条记录有五个域,下面是一个记录的格式。 
: llaaaatt[dd。。。]cc 
         每一组字母是独立的一域,每一个字母是一个十六进制数字,每一域至少由两个十六进制数字组成,下面是字节的描述。 
         : 冒号 是每一条Intel HEX记录的开始 
         ll 是这条记录的长度域,他表示数据(dd)的字节数目。 
         aaaa 是地址域,他表示数据的起始地址 
         tt 这个域表示这条HEX记录的类型,他有可能是下面这几种类型 
         00 —-数据记录 
         01 —-文件结束记录 
         02 —-扩展段地址记录 
         04 —-扩展线性地址记录 
         dd 是数据域,表示一个字节的数据,一个记录可能有多个数据字节,字节数目可以 
查看ll域的说明
         cc 是效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有字母对
所表示的十六进制数字 
         都加起来然后模除256得到的余数最后求出余数的补码即是本效验字节cc。 
         : 0300000002005E9D 
         cc=0×01+NOT((0×03+0×00+0×00+0×00+0×02+0×00+0×5E)%0×100)=0×01+0×9C=0×9D > 
         数据记录 
         Intel HEX文件由若干个数据记录组成,一个数据记录以一个回车和一个换行结束 
比如下面的一条数据记录 
         : 10246200464C5549442050524F46494C4500464C33 
         10 是此行记录数据的字节数目 
         2462 是数据在内存中的起始地址 
         00 是记录类型00(是一个数据记录) 
         464C 到 464C 是数据 
         33 是此行记录的效验和 

三、BIN

         BIN文件就是直接的二进制文件,内部没有地址标记。一般用编程器烧写时从00开始,而如果下载运行,则下载到编译时的地址即可。

         总结:可以由ELF文件转化为其它两种文件,HEX也可以直接转换为BIN文件,但是BIN要转化为HEX文件必须要给定一个基地址。而HEX和BIN不能转化为elf文件,因为ELF的信息量要大。另外还有一种ads的调试文件axf,
         它可以转化为BIN文件,用以下命令 fromelf -nodebug xx。axf -bin xx。bin即可。


 


 


 这里所说的ARM系统基本文件格式,都是在基于ARM的嵌入式系统开发中常会碰到的文件格式。
    ARM系统基本文件格式有三种:
1) BIN,平板式二进制格式,一般用于直接烧写到Flash中,也可以用于加载到monitor程序中。
2) ELF,EXECUTABLE AND LINKABLE FORMAT,一种通用的OBJECT文件格式,一般由GNU COMPILER COLLECTION (GCC)产生。
3) AXF,BIN格式的扩展版,主体部分同BIN,在文件头和尾加入了调试用的信息,用于AXD。
    本文主要讨论BIN与ELF。
    首先说明,ELF格式是一种OBJECT文件格式。一般OBJECT文件都可以分成三类:可重定位OBJECT文件,可执行OBJECT文件,共享OBJECT文件。ELF格式文件也可以分成这三种。
    首先说说可重定位OBJECT文件。这种OBJECT文件一般由GCC中的ASSEMBLER(as)产生(请不要认为GCC只是编译器),里面除了二进制的机器代码,还有一些可用于进行重定位的信息。它主要是作为LINKER(ld)的输入,LINKER将跟据这些信息,将需要重定位的符号重定位,进而产生可执行的OBJECT文件。ELF格式的可重定位OBJECT文件由header与section组成。
    Header 包括ELF header 与 section header. ELF header 位于文件的头部,用于存储目标机器的架构,大小端配置,ELF header大小,object文件类型,section header 在文件中的偏移,section header    的大小,section header 中的项目数等信息。Section header 则定义了文件中每个section 的类型,位置,大小等信息。Linker就是通过查找ELF header,找到section header 的入口,再在section header 中找到相应的section 入口,进而定位到目标section 的。
    Section 包括 
.text    :经过编译的机器代码。
.rodata  :只读的数据,例如printf(“hello!”)中的字符串hello。
.data    :已初始化的全局变量,局部变量将在运行时被存放在堆栈中,不会在.data或 .bss段中出现。
.bss     :未初始化的全局变量,在这里只是一个占位符,在object文件中并没有实际的存储空间。
.symtab  :符号表,用于存放程序中被定义的或被引用到的全局变量和函数的信息。
.rel.text  :一个保存着一系列在.text中的位置的列表。这些位置将在linker把这个文件与其它object文件合并时被修改,一般来说,这些位置都是保存着一些引用到全局变量或者外部函数的指令。引用局部变量或者本地函数的指令是不需要被修改的,因为局部变量和本地函数的地址一般都是使用PC相对偏移地址的。需要注意的是,这个section 和下面的.rel.data在运行时并不需要,生成可执行的ELF object文件时会去掉这个section。
.rel.data :保存全局变量的重定位信息。一般来说,如果一个全局变量它的初始化值是另一个全局变量的地址,或者是外部函数的地址,那么它就需要被重定位。
.debug  :保存debug信息。
.strtab  : 一个字符串表,保存着.symtab和.debug ,和各个section的名字。.symtab,.debug 和section table里面,凡是保存name的域,其实都是保存了一个偏移值,通过这个偏移值在这个字符串表里面可以找到相应得字符串。
    下面仔细讨论一下.symtab:
    每一个可重定位的object文件,都会有一个.symtab。这个符号表保存了在这个object文件中所有被定义的和被引用的符号。当源程序是C 语言程序时,.symtab 中的符号直接来源于C编译器(cc1)。这里所说的符号主要有三种:
1) 在这个object文件中被定义的可以被其他object文件全局符号。在C语言源程序中,主要就是那些非静态(没有static 修饰的)的全局变量和非静态的函数。在ARM汇编语言中,就是那些 被EXPORT 指令导出的变量。
2) 在这个object文件中引用到,但是在其他文件中定义的全局变量。在ARM汇编语言中就是通过IMPORT命令引入的变量
3) 本地变量。本地变量只在本object文件内可见。这里的本地变量指的是连接器本地变量,应该和一般的程序本地变量作区别。这里所指的本地变量,包括用static 修饰的全局变量,object文件中section名称,源代码文件名称。一般意义上的本地变量,是在运行时由系统的运行时环境管理的,linker并不关心。
    每个符合上面条件的符号在.symtab文件中都会有一个数据项。这个数据项的数据结构是:

Typedef struct{
    int name;//符号名称,其实就是.strtab的偏移值
    int value;//在section中的位置,以相对section地址的偏移表示
    int size;//大小
    char type;//类型,一般是数据或函数
    char binding;//是本地变量还是全局变量
    char reserved;//保留的位
        char section;//符号所属的section。可选有:.text(用数字1代表),.data(用数
                            //3代表),ABS(不应被重定位的符号),UND(在本object文件
                            //中未定义的符号,可能在别的文件中定义),COM(一般的未初//始化的变量符号)。
}ELF_sym

    现在假设组成应用的各个模块都已经被汇编,构建出了可重定位的object文件。这些object的结构都是一样的,有各自的.text, .data section, 有各自的.symtab. GCC下一步要做的就是使用linker (ld),把这些object文件,加上必要的库连接成具有绝对运行时地址的可执行文件,就是可执行的ELF格式的文件。
    Linker 的连接动作可以分为两部分:
1) 符号解析。确定引用符号的指向。
2) 符号重定位。合并section,    分配运行时环境地址,引用符号重定位。
    符号解析:
    在一个object文件中,有指令定义了符号,也有指令引用了符号。可能存在这样一种情况,一个被引用到的符号,有多重的定义。符号解析的作用就是确定,在这个object文件中,一个符号引用真正引用的是哪个符号。
    在编译的时候,除了在本文件中定义的全局变量会由编译器生成一个符号表项之外,当发现一个被引用到的符号在本文件中并没有被定义,编译器也会自动产生一个符号表项,把确定这些引用的工作留给linker。汇编器在汇编时将读取这些符号表项,生成.symtab。在读取的过程中,如果发现有在无法确定的符号引用项,汇编器会为这些符号额外生成一个数据项,称作重定位数据项,存放于rel.text或rel.data section中,交由linker确定。下面是重定位数据项(relocation entry)的数据结构:

Typedef struct{
    int offset;//指明需要被重定位的引用在object中的偏移,实际上就是需要被重定位的引用
                   //在object中的实际位置
    int symbol;//这个被重定位的引用真实指向的符号
    int type;//重定位类型:R_ARM_PC24:使用24bit的PC相对地址重定位引用
          //R_ARM_ABS32:使用32bit绝对地址重定位引用
}Elf32_Rel

    Linker 需要解析的,就是那些被生成了重定位数据项的引用。Linker将根据C语言定义的规则,对于每一个重定位数据项,在输入的各个object文件中查找适合的符号,把这个符号填入symbol项中。但是由于还不知道这个符号的真实地址,所以现在就算知道了引用的真实指向,但我们还是不能确定这个引用指向的地址。
    符号重定位:
    符号重定位用来解决上面的问题。Linker首先进行section 的合并。Linker合并object文件的过程很简单,一般就是相同属性的section合并,例如不同object文件的.text section 将被合并成一个.text。同样,.symtab section也被合并成一个.symtab。这里面涉及到两个问题:
1) 各个object文件合并的顺序。这个问题涉及到最终指令和符号的运行地址。最为重要的是,究竟是哪个section排在最前头?在ARM RAW 系统得开发过程中,这个最为重要。ARM系统CPU上电后,系统会自动的从0x00000000地址取指令并执行,这个地址上映射着存储器。这个动作是不可编程的。所以排在最前面的section一定要包含有程序的入口点,否则系统无法正常运行。
2) 输入段与输出端之间的对应关系。理论上,任何section,都可以被随意的映射到一个输出段中。一个.data section是可以与一个.text section 组成输出一个.text的。当然这样的动作毫无意义。我们必须告诉linker使用那些section作为输入,产生一个输出section.
    以上这两个问题,都是通过一个称为连接脚本的文件控制的。Linker通过读取连接脚本,来决定section 从输入到输出的映射,设置程序的入口点,设置哪个section应该在整个可执行文件的头部等问题。
    连接脚本还有另外一个作用,那就是指定每个section的地址。在section 合并完成后,linker将跟据.symtab,对符号进行统一的编址,分配一个绝对的运行时地址。这个地址是以section地址作为基地址的。假设.text section的地址是0x00000000,那么.text里面的符号将以0x00000000这个地址作为基准地址。指定section地址的工作也是由连接脚本完成。在嵌入式开发中常见的在编译工程时需指定的text_base, data_base等参数,最后会被加入到连接脚本中,从而完成section的地址分配。
    以上两步完成后,linker 执行引用符号重定位操作。Linker遍历.rel section (包括.rel text 和 .rel data),对于其中的每个数据项,根据symbol域到.symtab 中查出相应的引用的真实地址(经过上面的地址分配,现在.symtab里面的符号都具有绝对的运行地址),再根据offset域提供的偏移,将这个地址填入相应的位置上。
    至此,符号重定位工作全部完成。Linker删除用于保存重定位信息的rel.text和rel.data section,加入一个segment header和 一个.init section。生成可执行的ELF格式的object文件。
    Segment header保存了用于操作系统内存映射的信息。.init section 包含了一个_init 的函数。程序加载时,操作系统的程序加载器通过读取segment header,将程序加载到用户内存空间,并根据segment header里面映射信息,分别将.text 段和.data段映射到适当的地址上。然后再调用.init中的_init函数,完成初始化工作。
    由于ELF文件具有通用性强的优点,现在流行的开发模式是,先通过编译工具生成ELF文件格式的可执行文件,在使用外部工具,抽离出ELF文件中的相应部分,生成BIN文件。例如著名的GNU bootloader U-Boot,就采用了这种做法,编译器工具集是GCC,BIN生成工具是elf2bin。ARM公司著名的开发环境ADS,虽然使用的是自家的armcc,和armcpp编译器,但他们的工作方式却是与GNU GCC如出一辙。

关键字:ARM开发  烧写文件  格式说明 引用地址:ARM开发各种烧写文件格式说明(ELF、HEX、BIN)

上一篇:ARM系列之RO、RW、ZI的分布及说明
下一篇:s3c2410 中断异常处理

推荐阅读最新更新时间:2024-03-16 15:02

ARM芯片开发学习(S5PV210)——icache、dcache介绍和如何开关icache
什么是icache、dcache cache是高速缓冲存储器,icache(instructions cache)是指令高速缓冲存储器,dcache(data cache)是数据高速缓冲存储器。存储介质的基本规律是读写速度越快单位存储容量的价格就越高,为了平衡存储速度和价格,计算机的采用分级的存储系统,按照读写速度由快到慢:CPU- 寄存器- cache- 内存- 外存。其中寄存器是在集成到Soc内部的,直接和CPU交互数据,数量有限;在性能高一些的计算机中,cache是可以采用多级的;内存一般是RAM,外存可以是磁盘、flash等。其中icache和dcache就是属于cache,icache用于缓存指令,dcache用于缓存数
[单片机]
ARM裸机程序开发17(堆栈寻址)
堆栈是一种数据结构,按先进后出的方式工作。使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶 当堆栈指针指向最后压入堆栈的数据时,称为满堆栈,而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈 同时又根据堆栈的生成方式,又可分为递增堆栈和递减堆栈,当堆栈由低地址像高地址生成时,称为递增堆栈。当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有4中堆栈的工作方式。 ◎ Full descending 满递减堆栈——FD 堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。 ARM-Thumb过程调用标准和ARM、Thumb C/C++ 编译器总是
[单片机]
Qemu搭建ARM vexpress开发环境(三)----NFS网络根文件系统
经过上一篇《Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核》,已经实现了通过u-boot加载Kernel启动开发板,并且挂载根文件系统,本文讲述通过NFS网络挂载根文件系统。 通过NFS网络根文件系统,可以实现开发板在通过u-boot启动内核后,通过NFS网络在别的PC主机上挂载根文件系统。对于开发调试阶段的工作学习提供了很大的便利,可以直接在Linux主机上开发、编译驱动或者APP,并将目标文件拷贝到NFS服务目录中进行使用(此时文件相当于被拷贝到了开发板的根文件系统中)。也可以在主机端直接修改rootfs文件系统中别的文件,等效于在开发板上直接修改。 本文来介绍NFS挂载网
[单片机]
ARM 系列 -- FS2410 开发板上的串口通信编程
一、目的 串口通信我们并不陌生,我们经常用串口来进行数据传输,可并不清楚它是如何工作的。那这一节我们就来揭开 ARM S3c2410 UART(Universal Asynchronous Receiver and Transmitter) 串口通信的神秘面纱。 二、代码 我们先来分析文件 crt0.s @ 文件 crt0.s @ 作用:设置堆栈指针 .text .global _start _start: ldr sp, =1024*4 bl main halt_loop: b halt_loop 你可能会有疑问,这个汇编文件有什么用?呵呵,这是因为我们的串口通信代码要用 C编写(用汇编可
[单片机]
ARM微处理器的指令集概述(二)——ARM应用系统开发详解笔记
一 跳转指令 跳转指令用于实现程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转: — 使用专门的跳转指令。 — 直接向程序计数器 PC 写入跳转地址值。 ARM 指令集中的跳转指令可以完成从当前指令向前或向后的 32MB 的地址空间的跳转,包括以下 4 条指令: — B 跳转指令 — BL 带返回的跳转指令 — BLX 带返回和状态切换的跳转指令 — BX 带状态切换的跳转指令 B B{条件} 目标地址 B指令是最简单的跳转指令。注意存储在跳转指令中的实际值是 相对当前PC值的一个偏移量,而
[单片机]
ARM系列 STM32F103RCT6 开发
简单介绍STM32F1XX系列可以有RTOS ,实时操作系统,也可以直接当单片机用. 功能有adc,dac,bkp,can,cec,crc,dbgmcu,dma,exti,flash,fsmc,gpio,i2c,iwdg,pwr,rcc,rtc,sdio,spi,tim,usart,wwdg,misc 具体芯片的每个接口是什么功能,不同的板子差别不大,毕竟是要符合芯片规范的。 开发环境基本都是WINDOWS(unix-like gcc) , 开发工具有 MDK-ARM(keil), EWARM(IAR),HiTOP, GCC(RIDE),TrueSTUDIO.. 开发IDE中集成了startup文件,gcc也集成了的启动文件
[单片机]
回顾2012:各半导体厂商竞相开发ARM内核MCU
2012年对半导体行业而言是严峻的一年。从年初到9月底,半导体的全球销售额同比少4.7%。在这一期间,全球最大的半导体厂商——英特尔的销售额为399亿美元,同比减少1%;ARM的销售额为6.503亿美元,不及英特尔的1.5%,但同比增长了14%,实现了2位数增长。推动其销售额增长的一大因素就是 ARM内核MCU 。该公司称,2012年第三季度(7~9月)ARM内核MCU的供货量同比增加了35%。 英飞凌加入ARM行列 实际上,各大半导体厂商纷纷在2012年宣布致力于ARM内核MCU业务。比如,英飞凌科技公司在1月发布了基于Cortex-M4的“XMC4000系列”。在欧洲,恩智浦半导体公司和意法半导体公司是ARM内核MCU
[工业控制]
ARM芯片使用权 LG加入移动处理器开发
  目前厂商之间的竞争已经从当年的像素之争转变到了如今的智能 手机 处理器的竞争上。而继三星之后,韩国另一家巨头厂商LG今日获得ARM使用许可后,也将正式开始进行移动芯片的研发。   LG此次获得了包括使用Cortex-A9双核以及Cortex-A15多核处理器架构的许可,也就是说LG将拥有定制它们规格的权利。另外LG还能够使用ARM Mali-T604图形芯片,也就是目前三星Galaxy S2所使用的Mali GPU的升级产品。    点评: 这对于用户来说无疑是一则好消息,而随着三星和LG的相继加入,意味着在未来的Android设备中,除了Tegra 2和Snapdragon芯片组,我们还将拥有更多的选择。
[嵌入式]
获<font color='red'>ARM</font>芯片使用权 LG加入移动处理器<font color='red'>开发</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved