天天看点

痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)

ELF全称Executable and Linkable Format,可执行连接格式,ELF格式的文件最早用于存储Linux程序,后演变到ARM系统上存储ARM程序

  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家讲的是嵌入式开发里的executable文件(elf)。

  第四、五节课里,痞子衡已经给大家介绍了2种output文件,本文继续给大家讲project生成的另一种output文件-executable文件,也是特别重要的output文件。

  文件关系:链接文件(.icf) + 工程文件(.ewp) + 可重定向文件(.o/.a) -> 可执行文件(.out/.elf)

  仔细看过痞子衡之前课程的朋友肯定知道,痞子衡在第四节课可重定向文件(.o/.a)里介绍的object文件在格式上其实跟本文要讲的elf文件是类似的,它们都属于ELF文件分支。只不是relocatable文件只是中间过渡文件,而本文要讲的elf却是标准的output文件,这个文件几乎包含了工程的所有信息,有了这个文件我们既可以在线调试工程,也可以将elf文件转换成image文件,直接下载image文件数据进芯片中脱机运行。今天痞子衡就为大家仔细分析elf文件。

  ELF全称Executable and Linkable Format,可执行连接格式,ELF格式的文件最早用于存储Linux程序,后演变到ARM系统上存储ARM程序。ELF文件(目标文件)格式主要三种:

可重定向文件:用来和其他的目标文件一起来创建一个可执行文件或者共享目标文件(也称object文件或者静态库文件,通常后缀为.o和.a的文件)。这个文件是用于编译和链接阶段。 可执行文件:用于生成应用image,载入存储器执行(后缀通常为.out或者.elf)。这个文件是用于加载执行阶段。 共享目标文件:用于和其他共享目标文件或者object文件一起生成可执行文件,或者和可执行文件一起创建应用image。(也称共享库文件,后缀为.so的文件)。这个文件既可用于编译和链接阶段,也可用于加载执行阶段。

  我们在ARM开发中更多接触的是前两种格式,第一种格式前面系列文章可重定向文件(.o/.a)已经介绍过,本文的主角是第二种格式-可执行文件。不管是哪种格式的ELF文件,其都可能包含如下三种基本索引表:

file header:一般在文件的开始,描述了ELF文件的整体组织情况。 program header:告诉系统如何创建image,可执行文件必须具有program header,而可重定向文件则不需要。 section header:包含了描述文件section的信息,每个section都有一个header,每一个header给出诸如section名称、section大小等信息。可重定向文件必须包含section header。

  既然知道了存在三种索引表,那么表的结构定义在哪里呢?github上的linux仓库里有具体定义,在elf.h头文件里。

Linux仓库:https://github.com/torvalds/linux.git elf.h路径:\linux\include\uapi\linux\elf.h

  打开elf.h文件便可找到三个表的原型定义,鉴于目前的ARM Cortex-M都是32bit,所以此处仅列出32bit下的表的原型:Elf32_Ehdr、Elf32_Phdr、Elf32_Shdr。

  所谓工欲善其事,必先利其器,在开始解析elf文件之前,我们必须先找到一款合适的解析工具,readelf就是GNU/Linux官方推出的专用解析工具。有了这个解析工具,我们便可以逐步分析elf文件。

  既然elf文件是Linux系统下常用的可执行文件格式,那么Linux社区一定会有配套的工具去解析它,是的,这个工具就叫readelf,在GNU工具集binutils里。

  GNU是“GNU's Not Unix”的递归缩写,又称为GNU计划,很多著名的开源软件及工具都是GNU开发的(比如大名鼎鼎的C语言编译器GCC)。binutils是GNU一系列binary小工具的集合,大家从下面的链接里找到官方binutils包。

主页:http://www.gnu.org/software/binutils/ 仓库:git://sourceware.org/git/binutils-gdb.git 下载:http://ftp.gnu.org/gnu/binutils/ 文档:https://sourceware.org/binutils/docs-2.29/binutils/index.html

  但是使用上述包里的readelf会有一个问题,上述工具是在Linux系统下使用的,而大家平常做ARM Cortex-M开发很多都是在windows平台下,那么怎么在windows下使用readelf工具呢?别急,cygwin给了我们帮助。

  Cygwin是一个在windows平台上运行的类UNIX模拟环境,是cygnus solutions公司(已被Redhat收购)开发的自由软件。它对于学习UNIX/Linux操作环境,或者从UNIX到Windows的应用程序移植,尤其是使用GNU工具集在Windows上进行嵌入式系统开发,非常有用。

Installer:http://cygwin.com/install.html Package:https://cygwin.com/packages/package_list.html

  下载安装好cygwin包后,便可在安装目录下\cygwin64\bin\找到x86_64-w64-mingw32-readelf.exe工具(痞子衡选择的是mingw64-x86_64-binutils包)。

  readelf.exe遵循标准的windows命令行用法,使用--help可以列出所有命令option及其简介,下面仅列出比较常用的option。

  万事俱备了,开始分析elf文件,以第三节课工程文件(.ewp)里demo工程为例。编译链接该工程可在D:\myProject\bsp\builds\demo\Release\Exe路径下得到demo.elf文件。该文件大小32612 bytes,显然这么精简的一个小工程image size不可能这么大,说明elf文件里的记录信息数据占比非常大。

  第一步首先分析file header,前面介绍里说过file header是放在文件最前面的。通过readelf -h命令可以获得file header解析后的信息。让我们来对照一下,使用HexEditor直接打开demo.elf可得到如下数据,仅取前52bytes(0x34)数据,因为Elf32_Ehdr大小就是52bytes:

  可以看到前16byte是e_ident[16],与解析后的Magic是一致的;再来验证prgram header偏移e_phoff=0x00007BFC,数量e_phnum=0x0001,大小e_phentsize=0x0020,也是与解析后的信息匹配的;余下可自行对照。

  再来分析program header,通过readelf -l命令可以获得program header解析后的信息。从上面可以得知header起始位置在demo.elf的31740 byte处(与file header里的e_phoff信息是对应的),header信息提示program data从offset 0x34开始,大小共0x4c4 bytes,Reset_Handler入口是0x41。继续在HexEditor查看31740处开始的32byte数据,因为Elf32_Phdr大小就是32bytes:

  可以看到p_offset=0x00000034,p_memsz=0x000004c4, 与上面解析后的信息是一致的;余下可自行对照。 这里的信息就比较重要了,因为这指示了整个image binary数据所在(知道了这个信息,我们便可以直接写脚本根据elf文件生成image binary),继续在HexEditor里看下去(仅截取部分显示):

  ARM系统的image前16个指针都是系统中断向量,我们可以看到SP=0x10002000, PC=0x00000041,这与上面解析的Reset_Handler入口是0x41是匹配的。

  再来分析section header,通过readelf -S命令可以获得section header解析后的信息。可以看到有很多个section,其中最重要的4个section是A0(readonly vector), P1(readonly code,data), P2(readwrite data, heap), P3(STACK)。具体分析,各位朋友自己试试看。

  通过readelf -s命令可以获得symbol list解析后的信息。可以看到有很多个symbol,痞子衡在这里仅列出应用工程里自定义的函数和变量,从symbol表里我们可以得知函数/变量在存储器中具体分配地址和长度,这对于我们进一步分析和调试应用是有帮助的。

  经过上一节对demo.elf里各个header的分析,此时我们便可以粗略地画出elf文件layout。

File offset

Data content

Data size in bytes

0x00000000

ELF file header

52

0x00000034

Image binary (Section4-A0 rw, .intvec中断向量表)

0x40

0x00000074

Image binary (Section5-P1 ro, readonly section(.text, .rodata...))

0x484

0x000004F8

Section8-20 (包含各种辅助调试和系统段.debug_xx, .iar.xx)

0x5E3E

0x00006336

NULL

0x2

0x00006338

Section1-.shstrtab字符串表

0xE6

0x00006420

Section2-.strtab字符串信息

0xB7C

0x00006F9C

Section3-.symtab符号信息

0xC60

0x00007BFC

ELF Program header

0x20

0x00007C1C

ELF Section headers (0 - 20)

21 * 40

  在今天的番外篇里,痞子衡给大家顺便介绍几款标准的elf文件转换成image文件的工具。

  至此,嵌入式开发里的executable文件(elf)文件痞子衡便介绍完毕了,掌声在哪里~~~

文章会同时发布到我的 博客园主页、CSDN主页、微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)

  最后欢迎关注痞子衡个人微信公众号【痞子衡嵌入式】,一个专注嵌入式技术的公众号,跟着痞子衡一起玩转嵌入式。

痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)
痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)
痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)

  衡杰(痞子衡),目前就职于恩智浦MCU系统部门,担任嵌入式系统应用工程师。

  专栏内所有文章的转载请注明出处:http://www.cnblogs.com/henjay724/

  与痞子衡进一步交流或咨询业务合作请发邮件至 [email protected]

  可以关注痞子衡的Github主页 https://github.com/JayHeng,有很多好玩的嵌入式项目。

  关于专栏文章有任何疑问请直接在博客下面留言,痞子衡会及时回复免费(划重点)答疑。

  痞子衡邮箱已被私信挤爆,技术问题不推荐私信,坚持私信请先扫码付款(5元起步)再发。

ARM