目录

1. 什么是可执行程序?

1.1可执行文件格式

ELF文件格式

HEX文件格式

COFF文件格式

BIN文件格式

2.可执行程序如何执行?

3.ELF格式解析

3.1ELF文件格式视图

3.2为什么需要区分两种不同视图?

3.3ELF Header结构

3.4 Section Header Table表

3.5 Program Header Table表

4. SkyEye支持运行哪些格式的可执行文件

load-binary命令

load-file命令


作为迪捷软件研发人员,有时与客户交流过程中,客户会问到:「我们的程序如何在你们的SkyEye(全数字实时仿真平台)上运行?你们支持运行什么格式的可执行文件?」,下面就来简单介绍下嵌入式可执行程序相关的内容。

1. 什么是可执行程序?

嵌入式系统由硬件系统和软件系统组成,因此为了使整个嵌入式系统运行起来,必须有相应的程序,我们一般所说的程序,实际上就是存储在硬件设备中的一些可执行代码。可执行代码包括嵌入式操作系统和应用软件。

可执行程序也可叫目标二进制程序,相同的源程序在不同的处理器架构编译工具链下编译链接后会生成对应架构平台下的可执行程序。因而不同架构平台下的可执行程序只能在对应的架构平台下运行,不能直接移植到其他平台下运行。例如Windows(X86指令集)下编译生成的exe程序不能在ARM(ARM指令集)目标平台下运行。

1.1 可执行文件格式

由于不同的开发环境与不同的硬件架构,存储于嵌入式存储设备中的可执行文件格式也不尽相同,但它们基本上包含以下一些典型的特征:

1. 可执行文件的一般信息,如:文件大小、创建时间,文件名,文件权限等。

2. 与硬件处理器架构相关的二进制代码和数据。

3. 符号表与符号重定位表。

4. 调试器需要的调试信息与一些下载时需要的一些信息。

不同的嵌入式环境中,其生成的可执行文件的格式也不相同,主要有以下几种:

ELF文件格式

Executable and linking format(ELF)文件是一种常用、可移植目标文件(object file)格式,它有三种主要类型:

1) 可重定位文件(Relocatable File):包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。

2) 可执行文件(Executable File):包含适合于执行的一个程序,此文件规定了exec() 如何创建一个程序的进程映像。

3) 共享目标文件(Shared Object File):包含可在两种上下文中链接的代码和数据。首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理,生成另外一个目标文件。其次,动态链接器(Dynamic Linker)可能将它与某个可执行文件以及其它共享目标一起组合,创建进程映像。

HEX文件格式

Intel HEX文件是记录文本行的ASCII文本文件,在Intel HEX文件中,每一行是一个HEX记录,由十六进制数组成的机器码或者数据常量。记录类型包括:记录数据域,文件结束域,扩展线性地址的记录,扩展段地址的记录。在上面的后2种记录,都是用来提供地址信息的。每次碰到这2个记录的时候,都可以根据记录计算出一个「基」地址。对于后面的数据记录,计算地址的时候,都是以这些「基」地址为基础的。HEX文件是包括地址信息的,在烧写或下载HEX文件的时候,一般都不需要用户指定地址。

COFF文件格式

通用对象文件格式(Common Object File Format),是一种很流行的对象文件格式。

COFF文件一共有8种数据,如下所示:

1. 文件头(File Header)

2. 可选头(Optional Header)

3. 段落头(Section Header)

4. 段落数据(Section Data)

5. 重定位表(Relocation Directives)

6. 行号表(Line Numbers)

7. 符号表(Symbol Table)

8. 字符串表(String Table)

BIN文件格式

BIN文件格式对二进制文件而言,其实没有「格式」。文件只是包括了纯粹的二进制数据。其内部没有地址标记,只包括了数据本身。一般用编程器烧写时,是需要指定地址信息的 。

一般来说,可以由elf文件转化为其它两种文件,hex也可以直接转换为bin文件,但是bin要转化为hex文件必须要给定一个基地址。而hex和bin不能转化为elf文件,因为elf的信息量很大。

elf格式文件转换bin文件的方法:

Objcopy -O binary xxx.elf xxx.bin

2. 可执行程序如何执行?

程序执行时所需要的指令和数据必须在内存中才可以正常运行,最简单的方法就是采用静态装载方法,即将程序运行所需要的指令和数据全都装入内存,这样程序就可以正常运行。

通过SkyEye搭建的虚拟目标系统其中包括存储设备(RAM、FLASH等)的仿真,SkyEye执行可执行程序的流程如下:

1. 解析可执行文件,把程序中的指令和数据信息写入到相应的内存中;

2. 解析可执行文件获取程序第一条运行PC地址,并把运行PC地址给到处理器PC寄存器;

3. 处理器根据PC寄存器中的地址从内存中读取指令,开始执行指令。

3. ELF格式解析

3.1 ELF文件格式视图

ELF文件格式提供了两种视图,分别是链接视图执行视图

链接视图是以(section)为单位,执行视图是以(segment)为单位。链接视图就是在链接时用到的视图,而执行视图则是在执行时用到的视图。上图左侧的视角是从链接来看的,右侧的视角是执行来看的。整个文件可以分为四个部分:

  • ELF header: 描述整个文件的组织。
  • Program Header Table: 描述文件中的各种segments,用来告诉系统如何创建进程映像的。
  • sections 或者 segments:segments是从运行的角度来描述elf文件,sections是从链接的角度来描述elf文件,也就是说,在链接阶段,我们可以忽略program header table来处理此文件,在运行阶段可以忽略section header table来处理此程序(所以很多加固手段删除了section header table)。从图中我们也可以看出,segments与sections是包含的关系,一个segment包含若干个section。
  • Section Header Table: 包含了文件各个section的属性信息。

程序头部表(Program Header Table)如果存在的话,告诉系统如何创建进程映像。

节区头部表(Section Header Table)包含了描述文件节区的信息,比如大小、偏移等。

下面以PowerPC架构的可执行文件为例进行说明:

通过GNU binutils的readelf工具来查看可执行文件相关信息。

1. 可以通过执行命令「readelf -S vxWorks」来查看该可执行文件中有哪些section。

2.通过执行命令readelf –segments vxWorks,可以查看该文件的执行视图。

由上面两图可以看出segment是section的一个集合,sections按照一定规则映射到segment。

3.2 为什么需要区分两种不同视图?

ELF文件被加载到内存中后,系统会将多个具有相同权限(flg值)section合并一个segment。操作系统往往以页为基本单位来管理内存分配,一般页的大小为4096B,即4KB的大小。

同时,内存的权限管理的粒度也是以页为单位,页内的内存是具有同样的权限等属性,并且操作系统对内存的管理往往追求高效和高利用率这样的目标。

ELF文件在被映射时,是以系统的页长度为单位的,那么每个section在映射时的长度都是系统页长度的整数倍,如果section的长度不是其整数倍,则导致多余部分也将占用一个页。而我们从上面的例子中知道,一个ELF文件具有很多的section,那么会导致内存浪费严重。这样可以减少页面内部的碎片,节省了空间,显著提高内存利用率。

3.3 ELF Header结构

ELF Header数据结构定义如下:

#define EI_NIDENT 16typedef struct {       unsigned char e_ident[EI_NIDENT];       ELF32_Half e_type;       ELF32_Half e_machine;       ELF32_Word e_version;       ELF32__Addr e_entry;       ELF32_Off e_phoff;       ELF32_Off e_shoff;       ELF32_Word e_flags;       ELF32_Half e_ehsize;       ELF32_Half e_phentsize;       ELF32_Half e_phnum;       ELF32_Half e_shentsize;       ELF32_Half e_shnum;       ELF32_Half e_shstrndx;}Elf32_Ehdr;

通过执行命令readelf -h vxWorks命令,可以看到ELF Header结构的内容。

45:代表字符E

4C:代表字符L

46:代表字符F

01:代表ELF32, 02代表ELF64

02:代表大端,01代表小端

01:版本

在ELF Header中我们需要重点关注以下几个字段:

  • e_entry:程序入口地址
  • 所谓程序进入点是指当程序真正执行起来的时候,其第一条要运行的指令的运行时地址。如上图vxWorks可执行文件的e_entry指向0x100000,即程序第一条执行的指令地址是0x100000。
  • e_ehsize:ELF Header结构大小
  • e_phoff、e_phentsize、e_phnum:描述Program Header Table的偏移、大小、结构。
  • e_shoff、e_shentsize、e_shnum:描述Section Header Table的偏移、大小、结构。
  • e_shstrndx:这一项描述的是字符串表在Section Header Table中的索引,值15表示的是Section Header Table中第15项是字符串表(String Table)。

3.4 Section Header Table表

一个ELF文件中到底有哪些具体的 sections,由包含在这个ELF文件中的 section head table(SHT)决定。在SHT中,针对每一个section,都设置有一个条目(entry),用来描述对应的这个section,其内容主要包括该 section 的名称、类型、大小以及在整个ELF文件中的字节偏移位置等等。

section head table数据结构定义如下:

/* * Section header  */struct Elf32_Shdr {  uint32_t        sh_name;  uint32_t        sh_type;  uint32_t        sh_flags;  uint32_t        sh_addr;  uint32_t        sh_offset;  uint32_t        sh_size;  uint32_t        sh_link;  uint32_t        sh_info;  uint32_t        sh_addralign;  uint32_t        sh_entsize;};

由上图可以看到vxWorks可执行文件Section Header Table中有18个条目,且索引为15确实为section header section string table,与上述ELF Header结构中显示的e_shnum和e_shstrndx的值是一致的。

3.5 Program Header Table表

程序头部(Program Header)描述与程序执行直接相关的目标文件结构信息。用来在文件中定位各个段的映像。同时包含其他一些用来为程序创建映像所必须的信息。

可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段或者系统准备程序执行所必须的其他信息。目标文件的「段」包含一个或者多个「节区」,也就是「段内容(Segment Contents)」。程序头部仅对可执行文件和共享目标文件有意义。

程序头部的数据结构如下:

/* * Program header  */typedef struct { Elf32_Word p_type; //此数组元素描述的段的类型,或者如何解释此数组元素的信息。   Elf32_Off p_offset; //此成员给出从文件头到该段第一个字节的偏移 Elf32_Addr p_vaddr; //此成员给出段的第一个字节将被放到内存中的虚拟地址 Elf32_Addr p_paddr; //此成员仅用于与物理地址相关的系统中。Elf32_Word p_filesz; //此成员给出段在文件映像中所占的字节数。可以为0。   Elf32_Word p_memsz; //此成员给出段在内存映像中占用的字节数。可以为0。 Elf32_Word p_flags; //此成员给出与段相关的标志。   Elf32_Word p_align; //此成员给出段在文件中和内存中如何对齐。 } Elf32_phdr;

4. SkyEye支持运行哪些格式的可执行文件

SkyEye支持上述ELF、COFF、HEX、BIN文件格式的加载和运行。

SkyEye常用的几种加载命令包括如下:

load-binary命令

命令说明:用于加载ELF、COFF和HEX文件格式的二进制文件。

load-binary     <cpuname><filepath>

参数:

描述:对于包含符号信息、调试信息等内容的二进制文件直接使用load-binary加载。

load-file命令

命令说明:用于加载BIN文件格式的二进制文件到指定的内存中。

load-file     <cpuname ><filepath><address>

参数:

描述:对于一些可执行文件需要从指定地址开始加载,使用load-file指定其加载地址。

load-bin-binary命令

命令说明:用于加载BIN文件格式二进制到指定内存并指定第一条运行PC地址

load-bin-binary     <cpuname><filepath><address><length><start_pc>

参数:

描述:对于一些bin文件需要指定其加载的加载地址、文件大小和PC起始地址,使用load-bin-binary进行加载。

关于嵌入式可执行程序,你了解多少?相关推荐

  1. 外网访问arm嵌入式linux_嵌入式Linux系统编程——文件读写访问、属性、描述符、API

    Linux 的文件模型是从 Unix 的继承而来,所以 Linux 继承了 UNIX 本身的大部分特性,然后加以扩展,本章从 UNIX 系统接口来描述 Linux 系统结构的特性. 操作系统是通过一系 ...

  2. 嵌入式开发中使用DDD进行调试

    在嵌入式程序开发过程中,程序员要进行大量的调试,以此验证程序的正确性,修改潜在的错误.调试器对于程序员来说是不可或缺的必备工具.在Linux环境中,有很多调试工具和调试辅助工具,例如GDB.XXGDB ...

  3. 嵌入式SQL程序的VC+SQL server 2000实现的环境配置

    嵌入SQL的C应用程序具体到VC++6.0, SQL Server2000 下调试可分为五步:1.环境初始化;2.预编译;3.编译;4.连接;5.运行.下面就其中重要的的操作方法给以详细说明. 1.环 ...

  4. 基于ARM的Qt Creator嵌入式开发环境搭建

    平台:ubnutu10.04 交叉编译器:arm-linux-gcc-3.4.1 第一步,准备相关文件 在Qt官方网站可以下载qt-everywhere-opensource-src-4.8.1.ta ...

  5. 嵌入式开发/调试辅助工具

    开发辅助工具开发环境组成通常开发环境由三部分组成: 构建环境:包括代码编写,程序编译,版本控制等功能. 调试环境:用于定位问题的辅助工具集 测试环境:用于验证目标程序是否满足用户要求的显性需求和隐性需 ...

  6. 嵌入式设备web服务器比较

    现在在嵌入式设备中所使用的web服务器主要有:boa.thttpd.mini_httpd.shttpd.lighttpd.goaheand.appweb和apache等. Boa 1.介绍 Boa诞生 ...

  7. uml+oopc嵌入式c语言开发精讲_当前火爆的嵌入式领域,为什么选择C语言作为开发语言?了解一下...

    C语言和嵌入式C编程有什么区别?其区别在于嵌入式的C语言是跑在嵌入式的开发板上的,CPU和电脑不一样,所以编译器也是不一样的,生成的可执行程序也是不一样的.选择嵌入式开发语言归结于嵌入式系统开发的特点 ...

  8. 能用文件的安卓c语言,使用android NDK将.C 文件编译为 手机 可执行程序或者.so

    现有这样一个helloworld.c的源文件,如下: #include int main(){ printf("Hello world!\n"); } 如何将它进行编译,并在And ...

  9. 嵌入式linux入门-常用命令介绍

    使用芯片手册的时候,会时常的看到芯片中有的位填写的数字有保留,那是为了以后芯片升级和扩展使用的,现在是不使用.如GPF4占用的[9:8] 00 = Input,01 = Output, 10 = EI ...

最新文章

  1. 某程序员吐槽自己追求某字节HR,暧昧半年,见面后却被告知是普通朋友!心态已崩!网友:别追HR!道行太深!...
  2. composer Failed to decode zlib stream
  3. POJ2817 WordStack(状压DP)
  4. 苹果手机看python文件大小_Python练习题:你有一个目录,装了很多照片,把它们的尺寸变成都不大于iPhone5分辨率的大小...
  5. [HDU3336]Count the string(KMP+DP)
  6. P4178 Tree
  7. 常用的HTTP响应头
  8. 计算机病毒怎么做图片解说,【虎子_游戏解说】计算机病毒防范的实施方法
  9. 彻底卸载流氓软件如360等 1. 使用卸载软件(附下载链接) 2. 安全模式删除两种方法
  10. STL 格式解析--文本以及二进制格式
  11. PyQt5的Label鼠标的划过和单击
  12. 注册表Regedit实现右键管理员权限运行notepad++打开文件
  13. GO语言-panic和recover
  14. 详讯:微软宣布446亿美元收购雅虎
  15. 如何清理和优化你的Mac:14个小技巧推荐给你!
  16. Docker 镜像和容器
  17. Windows Server 中 DNS 服务器的新增功能
  18. 虚幻引擎 4 14 版发布
  19. 数据库原理与设计P163习题9答案
  20. RPM的制作(.spec文件)

热门文章

  1. python 调用控制台并获取返回结果_python脚本执行CMD命令并返回结果的例子
  2. python支持向量机分类器怎么用_可视化SVM分类器开源实现的python代码
  3. svpwm仿真_【好物推荐】《现代永磁同步电机控制原理及MATLAB仿真》
  4. linux device_create_file属性 怎么调用,device_create_file创建多级目录
  5. 深度学习中的损失函数如何画图_如何用深度学习来做检索:度量学习中关于排序损失函数的综述(1)...
  6. 在容器内源码安装PostgreSQL13.2
  7. 用诗歌描写计算机课,小班诗歌公开课教案范文【3篇】
  8. vs2008下如何部署arcengine开发的程序
  9. 计算机学院毕业典礼口号,毕业典礼口号
  10. mysql的基本数据类型总结_Mysql数据类型的详细总结