精华内容
下载资源
问答
  • 目标文件是源代码经过编译但未进行链接的那些中间文件,在linux中的.o文件,它跟可执行文件的内容与结构很相似,所以一般与可执行格式采用一方式存储,在linux下,我们可以将他们统称ELF文件。ELF文件标准里面把...

    ELF文件、目标文件、可执行文件的关系

    目标文件是源代码经过编译但未进行链接的那些中间文件,在linux中的.o文件,它跟可执行文件的内容与结构很相似,所以一般与可执行格式采用一种方式存储,在linux下,我们可以将他们统称ELF文件。ELF文件标准里面把系统中采用ELF格式的文件归为四类:

    ELF文件类型 说明 实例

    可重定位文件(Relocatable File)

    这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也属于这一类

    linux的.o

    windows的.obj

    可执行文件

    (Executable File)

    这类文件包含了可以直接执行的程序,它的代表就是ELF可执行文件,它们一般都没有扩展名

    比如/bin/bash文件;window的.exe 

    共享目标文件

    (Shared Object File)

    这种文件包含了代码和数据,可以在以下两种情况下使用。一种是连接器可以使用这种文件跟其他的可重定位文件和共享目标文件链接,产生新的目标文件。第二种是动态链接器可以将几个这种共享目标文件与可执行文件结合,作为进程映像的一部分运行。

    linux的.so,如/lib/glibc-2.5.so

    windows的DDL

    核心转储文件

    (Core Dump File)

    当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件。 linux下的core dump

    以以下代码编译出来的目标文件作为分析对象:

    #include <stdio.h>
    int global_init_var = 84;
    int global_uninit_var;
    
    void func1(int i)
    {
    	printf("%d\n",i);
    }
    
    int main(void)
    {
    	static int static_var = 85;
    	static int static_var2;
    	int a = 1;
    	int b;
    	func1(static_var + static_var2 + a + b);
    	return a;
    }
    

     使用objdump -h SimpleSection.o命令打印各个段的基本信息:

    如上图显示共有代码段、数据段、BSS段、只读段、注释信息段和堆栈提示段。对应的信息size表示段的长度,VMA File off表示段所在的位置。每个段的第二行中的“CONTENTS”、“ALLOC”等表示段的各种属性;其中“CONTENTS”表示该段在文件中存在。

    .text代码段:可以使用objdump 命令;-s 参数可以将所有段的内容以十六进制的方式打印出来。-d参数可以将所有包含指令段反汇编。我们将关于代码段的信息提取出来

    Contents of section .text下就是.text段的内容,总共0x51,与使用-h参数输出的.text长度一致,最左边是偏移量,中间是十六进制的内容,最右边是.text段的ASCII码形式。对照下边的反汇编结果,可以很明显的看到fun1和mian函数,.text段的第一个字节"0x55"就是func1()函数的第一条“push %ebp”指令,而最后“0x50”正好是main函数的最后一条指令“ret”。

     

    .data数据段:保存初始化了的全局变量和局部静态变量。global_init_var 和static int static_var。大小正好是8个字节。

     

    .bss段:存放的是未初始化的全局变量和局部静态变量。也就是说global_uninit_var和static_var2应该存放在.bss段,准确来说.bss段位他们预留了位置,本应该是8个字节,而我们使用objdump -h命令显示的size是4个字节。事实上只有static_var2存放在了.bss段,而global_uninit_var只是一个未定义的“COMMON”符号;这和编译器有关,有的编译器将全局未初始化变量存放在.bss段,有的则不存放,只是预留一个未定义的全局变量符号,等到最终链接后再分配到.bss段。

     

    .rodata段:存放的是只读数据,一般是程序里面的只读变量(如const修饰的变量)和字符串常量。在func1里面我们在调用“printf”的时候,用到了一个字符串常量“%d\n”,是4个字节与前面的长度符合。

    上面通过一个实例大致了解了ELF文件的基本轮廓,总的来说就包括了指令和数据。下图是ELF文件的总体结构:

    上面讲述了指令段和数据段,以下是ELF文件中其它的几个重要结构:

     

    文件头(ELF Header)

     

    ELF32_Ehdr和 ELF64_Ehdr结构体定义了ELF文件头的相关信息;这两个结构体的成员信息一致,只不过一个是32位版本的,另一个是64版本的。这里以ELF32_Ehdr为例,定义如下:

    我们可以使用readelf查看SimpleSection的目标文件头:

    e_ident(ELF魔数):该成员与readelf输出的Magic、Class、Data、Version、OS/ABI、ABI Version对应。 readelf输出的Magic的16字节正好对应e_ident这个成员;对于ELF文件前四个字节都必须相同,分别为0x7F、0x45、0x4c、0x46第一个字节对应ASCII控制,后面三个字节刚好是ELF这三个字母的ASCII,这4个字节称为ELF魔数,这种魔数用来确认文件的类型,操作系统在加载可执行文件的时候会确认魔数是否正确,如果不正确会拒绝加载。下一个字节对应Class用来表示ELF文件类的;第六个字节对应Data规定ELF文件是大端还是小端,第七个字节规定ELF文件的主版号,一般是1。对应的数据如下图所示

    e_type(文件类型):对应 readelf输出的Type表示ELF文件类型。包括REL (可重定位文件)、EXEC(可执行文件)、DYN(共享文件);系统是根据这三个常量判断文件类型,而不是扩展名。

    剩下的成员与readelf输出的参数,一一对应,此处不再赘述。综上文件头中描述整个文件的基本信息,以及段表的位置和大小、程序头的位置和大小。

     

    段表(Section header Table)

    段表是ELF文件中除了头文件以外最重要的结构,它描述了各个段的信息,比如段的段名、长度、在文件中的偏移、读写权限等等。段表是以一个元素是“ELF32_Shdr”结构体的数组。数组中的每一个元素对应一个段。ELF32_Shdr结构体的定义如下:

    使用readelf -S SimpleSection.o查看目标文件的段表

    根据上图,总共有11个元素,ELF段表文件的第一个元素时无效的,所以有效的段描述符有十个,也就是说有十个有效的段。readelf命令的输出与ELF32_Shdr结构体定义的成员一一对应,以下是对部分参数的详细解释:

    sh_type(段的类型):对应readelf命令输出的Type。段名只是在链接和编译过程中有意义,但是不能代表段的类型。比如我们有可以将一个数据段命名为.text。段对应的类型如下图所示:

    sh_flag(段的标志位):对应readelf命令输出的Flg;段的标志位是指该段在进程虚拟空间中的属性。比如是否可执行、可写。对应的值如下图所示:

    sh_link、sh_info(段的链接信息):如果段的类型是与链接有关的,比如重定位、符号表。那么这两个成员的意义如下图所示,对于其他段这两个参数没有意义。

     

    重定位表(Relocation Table)

    重定位是链接器对目标文件中的某些部分进行地址的重新定义。这些信息都会记录在重定位表中 。可能会注意到在讲述段表的时候,使用readelf -S命令输出中就有一个“rel.text”段,该段就是重定位表,并且是作用域.text段,它对应类型是“SHT_REL”。回顾我们最开始写的SimpleSetion文件有对“printf”函数的调用,这个就是引用了绝对地址。它所对应的sh_link的值9也就是说该重定位表使用的符号表在段表中的下标是9;h_info的值为1,表示该重定位表作用于的段在段表的下标,即.text。对比上图段表的信息,与此处结果符合。

     

    字符串表

    ELF文件中用到了很多的字符串,比如段表、变量名。因为每个字符串的长度不一,所以将所有的字符串放到一张表中,如下图所示:

    那么偏移与所对的字符串的关系:

    在使用字符串时,只需给出对应的偏移值即可。保存字符串常见的有.strtab和.shstrtab,分别存放普通字符串和段名字符串。在头文件结构中有e_shstrndx这样一个参数,表示是段表字符串在段表中的下标。所以,只有分析文件头,就可以得到段表和段表字符串的位置,从而解析整个elf文件。

     

    符号表(Symbol Table)

    符号的作用是当多个不同目标链接时函数和变量之间的相互引用。对于链接而言,只关心全局符号的相互引用。局部符号、段名、行号等符号是次要的。ELF文件中符号也是在一个符号表中,是一个ELF_Sym结构;结构定义如下:

    使用  readelf -s SimpleSection.o查看目标文件的符号表:

    详解:

    st_value(符号值):分为以下几种情况

    • 在目标文件中,如果是符号的定义并且该符号不是“COMMON”(未初始化的全局符号)类型,则st_value表示该符号在所在段中中的偏移,即符号所对应的函数或变量位于由st_shndx指定的段,偏移st_value的位置。
    • 在目标文件中。如果符号是“COMMON”类型的,则st_value表示该符号的对齐属性。
    • 在可执行文件中,st_value表示符号的虚拟地址。

    st_info(符号类型和绑定信息):低四位表示类型;高28位表示符号绑定信息。具体数值如下图所示:

    st_shndx(符号所在段):如果符号定义在本文件中,那么这个成员表示符号所在段在段表中的下标;还有几种特殊的情况,如下图所示:

     

    展开全文
  • Scratch 3的作品(sb3格式的文件)怎么生成可执行exe文件  Scratch 3.0界面如下:   【新版特征】  与以前2.0版本不同,Scratch3.0版本使用H5和JS语言编写,打破了电脑端和移动端的壁垒,有望在后期实现...

    Scratch 3的作品(sb3格式的文件)怎么生成可执行exe文件

       Scratch 3.0和Scratch 2.0软件相比,界面和内部实现机制有了较大变化。

     Scratch 3.0界面如下:

      

      与以前2.0版本不同,Scratch3.0版本改用H5和JS语言编写;软件界面有较大变化,将变成编程序区块放在了中间,更有利于成品的预览,以及编程和实际图形的对比,减少了重复无效的点击率;Scratch3.0整合并添加了插件模块,使用的文字朗读插件、翻译插件、Makey Makey插件等等大大提高了成品的质量与丰富度;在Scratch 3.0中文版中你可以完全采用简体中文。

     

    scratch项目(.sb格式)怎么生成可执行exe文件

    制作完成的scratch项目(.sb格式)想要分享给更多的人,若想在没有安装scratch程序运行,或 只能让他人运行演示而不能看到代码,如何实现呢?

    对于.sb2格式可以使用scratch2exe工具,安装完成后,运行软件,界面如下:

    点击1找到刚才保存的小程序选择打开。

      点击2,选择一个ico文件作为小程序的图标。

      第三步点击小绿旗,完成以上三步操作,点击确定,此时你会发现电脑中多了一个可执行的exe文件。

      双击这个exe文件,就可以正常出现游戏界面。

     

    对于.sb3格式上述方法已经不能用。对于.sb3格式怎么生成可执行exe文件?

    Scratch3.0产生的文件是sb3文件,目前需要使用方法如下:

    参考https://scratch.mit.edu/discuss/topic/341617/?page=1

    先到https://nwjs.io/ 下载压缩包nwjs,如nwjs-v0.39.3-win-x64.zip,解压备用。

    再到http://revocue.cz/en/make-sfx/index.php 下载makesfx.exe,(它不需要安装双击就运行)。

    以下是将sb3转换为exe的步骤:

    1.先转换为HTML5网页版本。打开https://sheeptester.github.io/words-go-here/scratch3-htmlifier/  网站,Upload project上传本地sb3文件,或者先把本地sb3文件上传到mit scratch社区上,得到一个项目号Project ID。选择HTMLify without minification(recommended)如下图所示,完成后会下载得到文件project.html(这是网页版的)。

     

    2.把下载的project.html移动到nwjs-v0.39.3-win-x64.zip解压后的目录。并在该目录下建立一个icon图标文件如a1.png,以及配置文件package.json文件(可以用记事本创建,注意文件的扩展名,如果含有中文字符,保存时编码选为UTF-8 如下图):

    package.json文件(其中的冒号引号等是英文的)内容包含:项目名字,主程序文件,图标,类似如:

    {

    "name": "您的应用程序或游戏名称",

    "main": "project.html",

    "icons": { “16”: “a1.png”}

    }

     注:“名称”和“图标”显示在窗口标题栏中。如果不用图标,则删除project.html后面的最后一个逗号和图标行,否则需要有一个png图标。

    此时,双击运行nw.exe,就可以预览效果了(但还未实际产生出一个exe文件)。

    要真正转换成的exe文件还需要进行下面的一步。

     

    3运行makesfx.exe,加入nw.exe,指定文件名和图标,制作成一个exe文件。参见下图:

     

    说明:

    1-源文件夹(可能包含子文件夹):包含nw.exe、package.json和所有其他文件的文件夹             

    2-目标SFX文件(exe文件):将在其中创建可执行文件            

    3-目标SFX文件图标:应用程序的图标。

    4-提取后将运行的可执行文件:进入nw.exe和package.json所在的文件夹,选择nw.exe   (其下命令行参数中不放置任何内容。)

    5-UAC自动提升:(如果您不是管理员)建议您使用最高可用权限运行sfx。

    您应根据实际情况填充内容,然后单击“MakeSfx”按钮,将构建一个可执行文件——exe文件,和原sb3文件相比,比较大。

    展开全文
  • ELF 文件规范   ELF(Executable and Linking Format)是一个二进制文件规范。...  现在流行的可执行文件格式 (Executable File Format),主要是 Windows 下的 PE(Portable Executable)和 Linux 的 EL...

    ELF 文件规范

      ELF(Executable and Linking Format)是一个二进制文件规范。用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。

      现在流行的二进制可执行文件格式 (Executable File Format),主要是 Windows 下的 PE(Portable Executable)和 Linux 的 ELF(Executable and Linking Format)可执行和链接格式)。他们都是 COFF(Common Object File Format)的变种。ARM 体系中采用的也是 ELF 文件格式。

      COFF 是在 Unix System V Release 3 时由 UNIX 系统实验室(UNIX System Laboratories, USL)首先提出并且使用的文件规范,后来微软公司基于 COFF 格式,制定了 PE 格式标准,并将其用于当时的 Windows NT 系统。在 System V Release 4 时,UNIX 系统实验室在 COFF 的基础上,开发和发布了 ELF 格式,作为应用程序二进制接口 (Application Binary Interface,ABI)。

      此后,工具接口标准委员会(Tool Interface Standard Committee,TISC)选择了正在发展中的 ELF 标准作为工作在 32 位 INTEL 体系上不同操作系统之间可移植的二进制文件格式。可以从这里 找到详细的标准文档。如下图:
    在这里插入图片描述
    TISC 共出过两个版本(v1.1和 v1.2)的标准文档。两个版本内容上差不多,但 v1.2 版本重新组织了原本在 v1.1 版本中的内容。可读性更高。两个版本的目录如下所示:
    在这里插入图片描述
    在 ELF 文件规范中,把系统中采用 ELF 格式的文件(规范中称为对象文件(Object File))归类为以下三种:

    • 可重定位文件(Relocatable File ): 这类文件包含代码和数据,可用来连接成可执行文件或共享对象文件(Object File),静态链接库归为此类,对应于 Linux 中的 .o ;Windows 的 .obj.
    • 可执行文件(Executable File ): 这类文件包含了可以直接执行的程序,它的代表就是 ELF 可执行文件。Linux 下,他们一般没有扩展名,比如 /bin/bash;Windows 下的 .exe
    • 共享对象文件(Object File)(Shared Object File ): 这种文件包含代码和数据,链接器可以使用这种文件跟其他可重定位文件的共享对象文件(Object File)链接,产生新的对象文件(Object File)。对应于Linux 中的 .so,Windows 中的 DLL
      另外是动态链接器可以将几个这种共享对象文件(Object File)与可执行文件结合,作为进程镜像文件来运行。

      在 Linux 系统中,还有一类文件,被称为核心转储文件(Core Dump File) ,当进程意外终止,系统可以将该进程地址空间的内容及终止时的一些信息转存到核心转储文件。 对应 Linux 下的 core dump。

      对象文件参与程序链接(构建程序)和程序执行(运行程序)。 为了方便和高效,对象文件(Object File)格式提供文件内容的并行视图,反映了这些活动的不同需求。 下图显示了对象文件(Object File)的组织。
    在这里插入图片描述
    其中,各部分的含义都是规范定义好的!
    在这里插入图片描述

    数据表示法

      对象文件(Object File)格式支持具有 8 位字节和 32 位体系结构的各种处理器。 然而,它旨在可扩展到更大(或更小)的体系结构。 因此,对象文件(Object File)用一种与机器无关的格式表示一些控制数据,从而可以识别对象文件(Object File)并以通用方式解释它们的内容。 目标处理器中的剩余数据使用目标处理器的编码,而不管创建文件的机器如何。出于可移植性的原因,ELF 不使用位字段。

    Name Size Alignment Purpose
    Elf32_Addr 4 4 Unsigned program address
    Elf32_Half 2 2 Unsigned medium integer
    Elf32_Off 4 4 Unsigned file offset
    Elf32_Sword 4 4 Signed large integer
    Elf32_Word 4 4 Unsigned large integer
    unsigned char 1 1 Unsigned small integer

      对象文件格式定义的所有数据结构都遵循相关类的自然大小和对齐准则。如果需要,数据结构包含显式填充,以确保 4 字节对象的 4 字节对齐,强制结构大小为 4 的倍数,以此类推。数据从文件开始也有适当的对齐。因此,例如,包含 Elf32 Addr 成员的结构将在文件中的 4 字节边界上对齐。

    字符表示法

      ELF 中对于符号的字符编码也有一定的要求。当 ELF 接口文档提到字符常量时,例如’/‘或’\ n’,它们的数值应遵循 7 位 ASCII 准则。 对于先前的字符常量,单字节值分别为 47 和 10。
      根据字符编码,在 0 到 127 范围之外的字符值可以占用一个或多个字节。 应用程序可以根据需要使用不同语言的不同字符集扩展来控制自己的字符集。 尽管 TIS-一致性 不限制字符集,但它们通常应遵循一些简单的指导原则:

    • 0 到 127 之间的字符值应对应于 7 位 ASCII 代码。 也就是说,编码大于 127 的字符集应包含 7 位ASCII 码作为子集。
    • 值大于 127 的多字节字符编码应仅包含值在 0 到 127 范围之外的字节。也就是说,每个字符使用多个字节的字符集不应嵌入类似于 7 位 ASCII 字符的字节。 一个多字节,非 ASCII 字符。
    • 多字节字符应该是自我识别的。 例如,这允许在任何一对多字节字符之间插入任何多字节字符,而不改变字符的解释。

    关于 ELF 文件规范这里就不多做详细介绍了,感兴趣的可以去 Linux 基金会的官方网站下载规范来看看!

    ARM ELF 文件格式

      ARM 体系中,所有文件均采用的 ELF 文件格式。我们可以在 ARM 的官网找到 ARM 关于 ARM ELF 文件格式的说明文档。后文参考部分的下载中是目前可以从 ARM 官网找到的所有和 ARM ELF 相关的 PDF 文档。

      目前,我们可以找到的 ARM ELF 相关的文档主要有 4 个:《ARM ELF File Format》、《ELF for the ARM® Architecture》、《ARM ELF》以及 ARM 的链接器手册。其中,《ARM ELF File Format》是比较早期的文档,针对于 ARM SDT 时代的 ELF 文件,有点过时了;后者三个则是最新的介绍文档,《ELF for the ARM® Architecture》 仅仅是对 ARM ELF 取值的一些特殊说明,是在读者先了解 ELF 文件规范的基础上进行的说明。

      ARM 中的各种源文件(包括汇编文件,C 语言程序及 C++ 程序等)经过 ARM 编译器编译后生成 ELF 格式的对象文件(Object File)(.o文件)。这些对象文件(Object File)和相应的 C/C++ 运行时用到的库经过 ARM 连接器处理后,生成 ELF 格式的镜像文件(image),这种 ELF 格式的映像文件是一种可执行文件,可被写入嵌入式设备的 ROM 中。

      在 ARM 体系中,所有的二进制文件均被称为对象文件。其中,链接器最终生成的 ELF 格式的可执行文件又被称为镜像文件(Image file)。ARM ELF 镜像文件或者对象文件由输入节(Input Sections)输出节(Output Sections)域(Regions)段(Segments) 组成,每个链接阶段都有不同的镜像视图。如下图所示:
    在这里插入图片描述

    • ELF object file view (linker input): ELF 对象文件视图由输入节组成。 ELF 对象文件可以是:

      • 一个可重定位文件,包含适合与其他对象文件(Object File)链接的代码和数据,以创建可执行文件或共享对象文件。
      • 包含代码和数据的共享对象文件。
    • Linker view: 连接器视图针对程序地址空间会有两个视图。并且这两个视图在存在重叠,位置无关和可重定位的程序片段(代码或数据)时变得不同:

      • 程序片段的加载地址是链接器期望外部代理(例如程序加载器,动态链接器或调试器)从 ELF 文件复制片段的目标地址。 这可能不是片段执行的地址。
      • 程序片段的执行地址是目标地址,其中链接器期望片段在参与程序的执行时驻留。

      如果片段与位置无关或可重定位,则其执行地址在执行期间可能会有所不同。

    • ELF image file view (linker output): ELF 镜像文件视图由程序段和输出节组成:

      • 一个加载域对应于一个程序段。
      • 一个执行域包含一个或多个以下输出节:
        • RO section.
        • RW section.
        • XO section.
        • ZI section.
      • 一个或多个执行域组成一个加载域。

    When describing a memory view:

    1. The term root region means a region that has the same load and execution addresses. 术语根区域是指具有相同加载和执行地址的区域。
    2. Load regions are equivalent to ELF segments. 加载区域等效于 ELF段。

    输入节 Input section

      一个输入节就是是输入对象文件中的一个独立的部分。 它包含代码,初始化数据,或着是描述未初始化或必须在镜像文件执行前设置为零的内存片段。 这些属性由 RO,RW,XO 和 ZI 等属性表示。 armlink 使用这些属性将输入节分组为更大的构建块,称为输出节和域。

    输出节 Output section

      一个输出节就是一组输入节的组合,它们具有相同的 RO,RW,XO 或 ZI 属性,并且由链接器连续放置在存储器中。 输出节与组成它的输入节具有相同的属性。 在输出节中,输入节根据节放置规则进行排序。

    域 Region

      一个域最多包含四个输出节,具体取决于内容和具有不同属性的节的数量。 默认情况下,域中的输出节根据其属性进行排序。 首先是 XO 属性的输出节,然后是 RO 属性的输出节,再然后是 RW 属性的输出节,最后是 ZI 属性的输出节。 域通常会映射到物理存储设备,例如 ROM,RAM 或外围设备。 您可以使用分散加载文件来更改输出节的顺序。

    程序段 Program segment

      一个程序段对应于一个加载域,并且包含执行域。 程序段包含文本和数据等信息。

    存在 XO( execute-only)节时的注意事项

    1. 您可以在同一执行域中混合 XO 和 非 XO 节。 但是,输出的结果是一个 RO 节。
    2. 如果输入文件具有一个或多个 XO 节,则链接器将生成单独的 XO ELF 段。 在最终镜像中,除非使用分散加载文件或 --xo-base 选项另有指定,否则 XO 段紧接在 RO 段之前。

    镜像的加载视图和执行视图

      镜像的域在加载时放置在系统存储器映射中。 内存中域的位置可能会在执行期间发生变化。在执行镜像之前,可能必须将镜像的某些域移动到其执行地址并创建 ZI 输出节。 例如,初始化的 RW 数据可能必须从其 ROM 中的加载地址复制到 RAM 中的执行地址。镜像的内存映射具有以下不同视图:

    加载视图 Load view

    根据镜像加载到内存中时所处的地址,即镜像执行开始前的位置,描述每个镜像的域和节。

    执行视图 Execution view

    根据镜像执行期间所在的地址描述每个镜像的域和节。

    下图显示了没有(XO)节的镜像的这些视图:
    在这里插入图片描述
    下图显示了具有 XO 节的镜像的加载和执行视图:
    在这里插入图片描述

    Image entry points

      镜像中的入口点就是镜像中的一个位置(地址),该位置(地址)会被加载到 PC 寄存器。 它是程序执行开始的位置。 虽然镜像中可以有多个入口点,但在链接时只能指定一个入口点。并非每个 ELF 文件都必须有入口点。 不允许在单个 ELF 文件中存在多个入口点。

      对于嵌入式 Cortex-M 核的程序,程序的执行是从复位向量所在的位置(地址)开始执行。复位向量会被加载到 PC 寄存器中,且复位向量的位置(地址)并不固定。 通常,复位向量指向 CMSIS Reset_Handler 函数。
    有两种不同类型的入口点:

    • 初始化入口点:镜像的初始入口点是存储在 ELF 头文件中的单个值。 对于那些需要由操作系统或引导加载程序加载到 RAM 中的程序,加载程序通过将控制转移到镜像中的初始入口点来启动镜像执行。一个镜像只能有一个初始化入口点。初始入口点可以是 ENTRY 指令设置的入口点之一,但不是必需的。
    • ENTRY 指令指定的入口点:可以为镜像从多个可能的入口点中选择其中一个。每个镜像只能有一个入口点。您可以在汇编程序文件中使用 ENTRY 指令在对象中创建入口点。 在嵌入式系统中,该指令的典型用途是标记进入处理器异常向量(例如 RESET,IRQ 和 FIQ)的代码。该指令使用 ENTRY 关键字标记输出代码部分,该关键字指示链接器在执行未使用的部分消除时不删除该部分。对于 C/C++ 程序,C 库 中的 __main 就是入口点。

    如果加载程序要使用嵌入式的映像,则它必须在标头中指定一个初始入口点。 使用--entry命令行选项选择入口点。

    ARM ELF 文件实例

      与标准的 ELF 文件相比,ARM ELF 的某些值比较特殊,下面以实际文件来说明一下每个部分。编译工具如下图:
    在这里插入图片描述
    编译后,会在对应目录下生成 .o 文件和 .axf 文件,为了分析 ELF 文件,我们将使用 readelf 工具。在详细解析之前,先用 Winhex 直接打开生成的 .o 文件,可以看到文件开头有 ELF 字样。表明它是一个 ELF 文件。如下:
    在这里插入图片描述
    注意:.o 不是 ARM 的可执行文件!axf 为可执行文件。以下用两种程序作对比。

      一个简单的可执行 ARM ELF 文件的概念布局如下图所示。请注意,文件中各部分的实际排序可能与下图中的顺序不同,因为只有 ELF Header 在文件中具有固定位置。
    在这里插入图片描述
    注意,针对目前最新版本的 ARM ELF,上图有点过时!

    ELF Header

      ELF Header 描述了体系结构和操作系统等基本信息,并指出 Section Header Table 和 Program Header Table 在文件中的什么位置。实际文件中,只有 ELF Header 位置是绝对的,且只能在最开始,其他部分部分的位置顺序并不一定完全相同。

      Program Header Table 在汇编和链接过程中没有用到,所以在重定位文件中可以没有;Section Header Table 中保存了所有 Section 的描述信息,Section Header Table 在加载过程中没有用到,对于可执行文件,可以没有该部分。当然,对于某些类型的文件来说,可以同时拥有 Program header table 和 Section Header Table,这样 load 完后还可以重定位。(例如:shared objects)

      ELF Header 可以使用如下数据结构表示:

    #define EI_NIDENT 16
    
    typedef struct {
        unsigned char   e_ident[EI_NIDENT]; // Magic
        Elf32_Half      e_type;             // Type
        Elf32_Half      e_machine;          // Machine
        Elf32_Word      e_version;          // Version
        Elf32_Addr      e_entry;            // Entry point address
        Elf32_Off       e_phoff;            // Start of program headers
        Elf32_Off       e_shoff;            // Start of section headers
        Elf32_Word      e_flags;            // Flags    
        Elf32_Half      e_ehsize;           // Size of this header
        Elf32_Half      e_phentsize;        // Size of program headers
        Elf32_Half      e_phnum;            // Number of program headers
        Elf32_Half      e_shentsize;        // Size of section headers
        Elf32_Half      e_shnum;            // Number of section headers
        Elf32_Half      e_shstrndx;         // Section header string table index
    } Elf32_Ehdr;
    

    下面两幅图分别显示了不同文件的 ELF Header。以上数据结构中的注释,即对应于下图中的各部分字段。
    .o 文件 ELF Header 如下图所示:
    在这里插入图片描述
    .axf 文件 ELF Header 如下图所示:
    在这里插入图片描述
    下面对以上两幅图中的内容做一下详细介绍:

    • 第 1 行 ELF Header:这是 readelf 工具的显示,实际文件中不存在这个符号!直接从 Magic 开始!
    • 第 2 行 Magic:用来指名该文件是一个 ELF 对象文件(Object File),对应于 Elf32_Ehdr 数据结构中的 unsigned char e_ident[EI_NIDENT];,使用以下宏值进行索引:
      名称 取值 意义
      EI_MAG0 0 文件标识
      EI_MAG1 1 文件标识
      EI_MAG2 2 文件标识
      EI_MAG3 3 文件标识
      EI_CLASS 4 文件类
      EI_DATA 5 数据编码
      EI_VERSION 6 文件版本
      EI_PAD 7 补齐字节开始处
      EI_NIDENT 16 e_ident[]大小
      e_ident[EI_MAG0] ~ e_ident[EI_MAG3]:包含了 ELF 文件的魔数,依次固定是 0x7f 和 ‘E’、‘L’、‘F’。
      e_ident[EI_CLASS]:取值如下
      名称 取值 意义
      ELFCLASSNONE 0 非法类别
      ELFCLASS32 1 32
      ELFCLASS64 2 64
      ARM ELF 文件应包含 ELFCLASS32。
      e_ident[EI_DATA]
      名称 取值 意义
      ELFDATANONE 0 非法数据编码
      ELFDATA2LSB 1 高位在前
      ELFDATA2MSB 2 低位在前
      选择将由执行环境中的默认数据顺序控制。 在以 BE8 模式运行的 Architecture v6 处理器上,所有的指令均为小端格式。 适合在此模式下操作的可执行文件将在 e_flags 字段中设置 EF_ARM_BE8。
      e_ident[EI_VERSION]:指定 ELF头部的版本,当前必须为 1。
      e_ident[7]~e_ident[15]:是填充符,通常是 0
    • 第 3 行 Class:该值就是 e_ident[EI_CLASS]
    • 第 4 行 Data:该值就是 e_ident[EI_DATA]
    • 第 5 行 Version:该值就是 e_ident[EI_VERSION]
    • 第 6 行 OS/ABI:该值应该是 e_ident 的扩展部分。操作系统类型,ABI 是 Application Binary Interface 的缩写。除非文件使用具有 OS 特定含义的标志(例如,使用 SHN_LOOS 通过 SHN_HIOS 的段索引),否则该字段应为零。 目前,该字段有一个特定于处理器的值,如下。
      取值 意义
      ELFOSABI_ARM_AEABI (64) 该对象包含符号版本控制扩展,如§3.1.1符号版本控制中所述。
    • 第 7 行 ABI Version: 该值应该是 e_ident 的扩展部分。版本号,当前为 0 。
    • 第 8 行 Type:表示该对象文件(Object File)类型(上图中的类型省略了ET_)。
      名称 取值 意义
      ET_NONE 0 未知对象文件(Object File)格式
      ET_REL 1 可重定位文件
      ET_EXEC 2 可执行文件
      ET_DYN 3 共享对象文件(Object File)
      ET_CORE 4 Core 文件(转储格式)
      ET_LOPROC 0xff00 特定处理器文件 ET_LOPROC 和 ET_HIPROC 之间的取值用来标识与处理器相关的文件格式。
      ET_HIPROC 0xffff 特定处理器文件
      目前没有特定于 ARM 的对象文件类型。 ET_LOPROCET_HIPROC 之间的所有值都保留给本规范的未来版本。
    • 第 9 行 Machine:机器平台类型。ARM 架构为 EM_ARM(上图中的类型省略了ET_)。
      Name Value Meaning
      EM_NONE 0 No machine
      EM_M32 1 AT&T WE 32100
      EM_SPARC 2 SPARC
      EM_386 3 Intel Architecture
      EM_68K 4 Motorola 68000
      EM_88K 5 Motorola 88000
      EM_860 7 Intel 80860
      EM_MIPS 8 MIPS RS3000 Big-Endian
      EM_MIPS_RS4_BE 10 MIPS RS4000 Big-Endian
      ……
      EM_ARM 40 ARM/Thumb Architecture
    • 第 10 行 Version:当前对象文件(Object File)的版本号。
      名称 取值 意义 说明
      EV_NONE 0 Invalid version
      EV_CURRENT 1 Current version 该项的取值可根据需要改变
    • 第 11 行 Entry point address:程序的虚拟地址入口点。在 ARM 中:
      • 在可执行 ELF 文件中,e_entry 是镜像唯一入口点的虚拟地址,如果镜像没有唯一入口点,则为 0。
      • 在可重定位ELF文件中,e_entry 是被 SHF_ENTRYSECT 所标记的段的入口点的偏移量,若没有入口点,则为 0。
      • Bit[0] = 1,表示 Thumb 指令;Bit[0:1] = 00,表示ARM指令;Bit[0:1] = 10,保留;
        平台标准可以指定可执行文件总是具有入口点,在这种情况下,e_entry 指定入口点,即使为零。
    • 第 12 行 Start of program headers:程序头的起始地址,.o 文件没有 Program Headers 。
    • 第 13 行 Start of section headers:节头的起始地址。上图中的 486388 是十进制,即:表示节头是从地址偏移 0x76BF4 处开始。
    • 第 14 行 Flags:是一个与处理器相关联的标志。
      名称 意义
      EF_ARM_ABIMASK (0xFF000000) (current version is 0x05000000) 此ELF文件符合的ARM EABI的版本,该值为一个8比特的掩码。 当前EABI是版本5。0表示未知符合。
      EF_ARM_BE8 (0x00800000) ELF文件包含适合在ARM Architecture v6处理器上执行的BE-8代码。 该标志只能在可执行文件上设置。
      EF_ARM_GCCMASK (0x00400FFF) gcc-arm-xxx生成的旧版代码(ABI版本4及更早版本)可能会使用这些位。
      EF_ARM_ABI_FLOAT_HARD (0x00000400) (ABI version 5 and later) 设置可执行文件头(e_type = ET_EXEC或ET_DYN)以标注可执行文件的构建是为了符合硬件浮点过程调用标准。 与旧版(预版本5)兼容,gcc用作EF_ARM_VFP_FLOAT
      EF_ARM_ABI_FLOAT_SOFT (0x00000200) (ABI version 5 and later) 设置在可执行文件头(e_type = ET_EXEC或ET_DYN)中明确标注可执行文件的构建符合软件浮点过程调用标准(基准标准)。 如果EF_ARM_ABI_FLOAT_XXXX位都清零,则默认符合基本过程调用标准。 与旧版(预版本5)兼容,gcc用作EF_ARM_SOFT_FLOAT。
      注意:以上部分与 ARM 早期文档是有区别的,很多值已经不同
    • 第 15 行 Size of this header:ELF 文件头的字节数。
    • 第 16 行 Size of program headers:Program Headers 大小。.o 文件大小为 0。
    • 第 17 行 Number of program headers:Program Headers 的数量(可以有多个)。
    • 第 18 行 Size of section headers:sections header 的大小
    • 第 19 行 Number of section headers:sections header 的数量。
    • 第 20 行 Section header string table index:节头部表格中与节名称字符串表相关的表项的索引。如果文件没有节名称字符串表,此参数可以为 SHN_UNDEF

    注意:实际文件中,每一部分的位置顺序并不一定完全相同,只有 ELF Header 位置是绝对的,且只能在最开始。

    Section Header(节头)

      节头表提供了对 ELF 文件中所有节的访问。节中包含对象文件(Object File)中的所有信息,除了:ELF 头部、程序头部表格、节头部 表格。节满足以下条件:

    1. 对象文件(Object File)中的每个节都有对应的节头部描述它,反过来,有节头部不意 味着有节。
    2. 每个节占用文件中一个连续字节域(这个区域可能长度为 0)。
    3. 文件中的节不能重叠,不允许一个字节存在于两个节中的情况发生。
    4. 对象文件(Object File)中可能包含非活动空间(INACTIVE SPACE)。这些区域不属于任何 头部和节,其内容未指定。

      ELF 头部中,e_shoff 成员给出从文件头到节头部表格的偏移字节数;e_shnum 给出表格中条目数目;e_shentsize 给出每个项目的字节数。从这些信息中可以确切地定位节的具体位置、长度。节头部表格中比较特殊的几个下标如下:

    名称 取值 说明
    SHN_UNDEF 0 标记未定义的、缺失的、不相关的,或者没有含义的节引用
    SHN_LORESERVE OxFF00 保留索引的下界
    SHN_LOPROC 0xFF00 SHN_HIPROC 0XFF1F 保留给处理器特殊的语义
    SHN_ABS 1 包含对应引用量的绝对取值。这些值不会被重定位所 影响
    SHN_COMMON 2 相对于此节定义的符号是公共符号。如 FORTRAN 中 COMMON 或者未分配的 C 外部变量。
    SHN_HIRESERVE 保留索引的上界

    介于 SHN_LORESERVESHN_HIRESERVE 之间的表项不会出现在节头部表中。

    .o文件 Section Header(部分)
    在这里插入图片描述
    .axf 文件 Section Header
    在这里插入图片描述
    上图中的表头可以用如下数据结构描述(对应关系见注释):

    typedef struct {
        Elf32_Word sh_name;         // name
        Elf32_Word sh_type;         // Type
        Elf32_Word sh_flags;        // Flg
        Elf32_Addr sh_addr;         // Addr
        Elf32_Off sh_offset;        // Off
        Elf32_Word sh_size;         // Size
        Elf32_Word sh_link;         // Lk
        Elf32_Word sh_info;         // Inf
        Elf32_Word sh_addralign;    // Al
        Elf32_Word sh_entsize;      // ES
    } Elf32_Shdr;
    
    • sh_name:给出节名称。是节头部字符串表节(Section Header String Table Section)的索引。名字是一个 NULL 结尾的字符串。ELF 文件规定一些标准节的名字,例如 .text、.data、.bss。此外,如上图中,许多节名字都是 ARM 自己扩展的。

    • sh_type:为节的内容和语义进行分类。ARM ELF 只使用了其中的一部分。参见下表(部分)。

      名称 取值 含义
      SHT_NULL 0 此值标志节头部是非活动的,没有对应的节。此节头部中的其他成员取值无意义。
      SHT_PROGBITS 1 此节包含程序定义的信息,其格式和含义都由程序来解释释。
      SHT_SYMTAB 2 此节包含一个符号表。目前对象文件(Object File)对每种类型的节都只能包含一个,不过这个限制将来可能发生变化。一般,SHT_SYMTAB 节提供用于链接编辑(指 ld而言) 的符号,尽管也可用来实现动态链接。
      SHT_STRTAB 3 此节包含字符串表。对象文件(Object File)可能包含多个字符串表节。
      SHT_RELA 4 此节包含重定位表项,其中可能会有补齐内容(addend),例如 32 位对象文件(Object File)中的 Elf32_Rela 类型。对象文件(Object File)可能拥有多个重定位节。
      SHT_HASH 5 此节包含符号哈希表。所有参与动态链接的目标都必须包含一个符号哈希表。目前,一个对象文件(Object File)只能包含一个哈希表, 不过此限制将来可能会解除。
      SHT_DYNAMIC 6 此节包含动态链接的信息。目前一个对象文件(Object File)中只能包含一个动态节,将来可能会取消这一限制。
      SHT_NOTE 7 此节包含以某种方式来标记文件的信息。
      SHT_NOBITS 8 这种类型的节不占用文件中的空间,其他方面和 SHT_PROGBITS 相似。尽管此节不包含任何字节,成员sh_offset 中还是会包含概念性的文件偏移
      SHT_REL 9 此节包含重定位表项,其中没有补齐(addends),例如 32 位对象文件(Object File)中的 Elf32_rel 类型。对象文件(Object File)中可以拥有多个重定位节。

      除了以上标准节类型外,ARM 架构下,还有以下特殊的类型:

      名称 取值 含义
      SHT_ARM_EXIDX 0x70000001 异常索引表
      SHT_ARM_PREEMPTMAP 0x70000002 BPABI DLL动态链接抢占地图
      SHT_ARM_ATTRIBUTES 0x70000003 对象文件兼容性属性
      SHT_ARM_DEBUGOVERLAY 0x70000004
      SHT_ARM_OVERLAYSECTION 0x70000005
    • sh_flags:字段定义了一个节中包含的内容是否可以修改、是否可以执行等信息。如果一个标志比特位被设置,则该位取值为1。未定义的各位都设置为 0。

      名称 取值 含义
      SHF_WRITE 0x1 节包含进程执行过程中将可写的数据
      SHF_ALLOC 0x2 此节在进程执行过程中占用内存。某些控制节并不出现于目标 文件的内存映像中,对于那些节,此位应设置为 0
      SHF_EXECINSTR 0x4 节包含可执行的机器指令
      SHF_MASKPROC 0xF0000000 所有包含于此掩码中的四位都用于处理器专用的语义

      ARM 中的特殊取值如下:

      Name Value Purpose
      SHF_ARM_NOREAD 0x20000000 本节的内容不应由程序执行者读取
    • sh_addr:如果节将出现在进程的内存镜像中,此成员给出节的第一个字节应处的位置。否则,此字段为 0。

    • sh_link 和 sh_info:根据节类型的不同,sh_link 和 sh_info 的具体含义也有所不同。ARM 取值如下:

      sh_type sh_link sh_info
      SHT_SYMTAB, SHT_DYNSYM 相关联的字符串表的节头部索引 最后一个局部符号(绑定 STB_LOCAL)的符号表索引值加一
      SHT_DYNAMIC 此节中条目所用到的字符串表格 的节头部索引 0
      SHT_HASH 此哈希表所适用的符号表的节头部索引 0
      SHT_REL、SHT_RELA 相关符号表的节头部索引 重定位所适用的节的节头部索引
      其它 SHN_UNDEF 0
    • sh_addralign:节没有最小对齐要求。 但是,包含 thumb 代码的部分必须至少为 16 位对齐,并且包含 ARM 代码的部分必须至少为 32 位对齐。具有 SHF_ALLOC 属性的任何节必须满足 sh_addralign >= 4。其他节可根据需要对齐。 例如,调试表通常没有对齐要求。并且输入到静态链接器的数据段可以自然对齐。
      平台标准可能会限制他们可以保证的最大对齐(通常是页面大小)。

    • sh_entsize:某些节中包含固定大小的项目,如符号表。对于这类节,此成员给出每个表项的长度字节数。如果节中并不包含固定长度表项的表格,此成员取值为 0。

    • sh_size:此成员给出本节的长度(字节数)。除非节的类型是 SHT_NOBITS,否则节占用文件中的 sh_size 字节。类型为 SHT_NOBITS 的节长度可能非零,不过却不占用文件中的空间。

    • sh_offset:此成员的取值给出节的第一个字节与文件头之间的偏移。不过,SHT_NOBITS 类型的节不占用文件的空间,因此其 sh_offset 成员给出的是其概念性的偏移。

    注意:

    1. 保留给处理器体系结构的节名称一般构成为:处理器体系结构名称简写 + 节名称。且处理器名称应该与 e_machine 中使用的名称相同。例如:上图最后的 .ARM.attributes
    2. 对象文件(Object File)中也可以包含多个名字相同的节。
    3. 上图节名 ER_IROM1、RW_IRAM1、RW_IRAM 是由连接器的分散加载文件指定的名称。可以根据需要自行修改。

      ARM 节名称是以下面列出的具有预定义含义的标准前缀之一开始的名称,或者是包含美元($)字符的名称。 在 ARM EABI 下没有其他具有特殊意义的段名称。

    节前缀名 节类型 节属性 解释
    .bss SHT_NOBITS SHF_ALLOC+SHF_WRITE 本节保存有助于程序内存映像的未初始化数据。 根据定义,当程序开始运行时,系统将使用零初始化数据。 该部分不占用文件空间,如段类型 SHT_NOBITS 所示。
    .comment SHT_PROGBITS None 本节包含版本控制信息
    .data SHT_PROGBITS SHF_ALLOC+SHF_WRITE 这些部分保存有助于程序内存映像的已初始化数据
    .data1 SHT_PROGBITS SHF_ALLOC+SHF_WRITE
    .debug… SHT_PROGBITS None 本节保存符号调试信息。 内容未指定。 具有前缀.debug的所有段名保留供将来使用
    .dynamic SHT_DYNAMIC SHF_ALLOC [+SHF_WRITE] 本节保存动态链接信息,并具有SHF_ALLOC和SHF_WRITE等属性。 操作系统和处理器确定SHF_WRITE位是否被置位
    .hash SHT_HASH [SHF_ALLOC] 本节包含一个符号哈希表。
    .line SHT_PROGBITS None 本节保存符号调试的行号信息,其中描述了源程序和机器代码之间的对应关系。 内容未指定
    .rodata SHT_PROGBITS SHF_ALLOC 这些部分保存通常有助于过程映像中的不可写段的只读数据
    .rodata1 SHT_PROGBITS SHF_ALLOC
    .rel name
    .rela name
    SHT_REL SHT_RELA [SHF_ALLOC] 这些节中包含了重定位信息。如果文件中 包含可加载的段,段中有重定位内容,节 的属性将包含 SHF_ALLOC 位,否则该位 置 0。传统上 name 根据重定位所适用的节 区给定。例如 .text 节的重定位节名字,将是:.rel.text 或者 .rela.text。
    .shstrtab SHT_STRTAB None 本节保存节名称。
    .strtab SHT_STRTAB [SHF_ALLOC] 此节包含字符串,通常是代表与符号表项 相关的名称。如果文件拥有一个可加载的 段,段中包含符号串表,节的属性将包含 SHF_ALLOC 位,否则该位为 0。
    .symtab SHT_SYMTAB [SHF_ALLOC] 此节包含一个符号表。如果文件中包含一 个可加载的段,并且该段中包含符号表,那 么节的属性中包含SHF_ALLOC 位,否则 该位置为 0。
    .text SHT_PROGBITS SHF_ALLOC+ SHF_EXECINSTR 本节包含程序的文本或可执行指令

    除了以上标准节外,ARM 架构下,还有以下特殊的节:

    节前缀名 节类型 节属性 说明
    .ARM.exidx* SHT_ARM_EXIDX SHF_ALLOC + SHF_LINK_ORDER 以.ARM.exidx开头的节包含部分展开的索引条目。
    .ARM.extab* SHT_PROGBITS SHF_ALLOC 以.ARM.extab开头的节包含异常展开信息的名称部分。
    .ARM.preemptmap SHT_ARM_PREEMPTMAP SHF_ALLOC 以.ARM.preemptmap开头的节包含一个BPABI DLL动态链接优先地图。
    .ARM.attributes SHT_ARM_ATTRIBUTES none 包含构建属性
    .ARM.debug_overlay SHT_ARM_DEBUGOVERLAY none
    .ARM.overlay_table SHT_ARM_OVERLAYSECTION See DBGOVL for details

      这里需要注意一下 Debug Sections。Debug Sections 仅在调试时使用,稍微复杂一些。ARM 可执行 ELF 文件的调试节中包含多种类型的调试信息,ELF 可执行文件的使用者(如armlink)可以通过检查可执行文件的节表来区分这些种类型的调试信息。

      ARM 系列的开发工具在不同的发展时期,采用的调试信息是有区别的,后来统一采用 DWARP。目前采用的应该是 3.0 版本。具体如下:

    • ASD debugging tables:
      These provide backwards compatibility with ARM’s Symbolic Debugger. ASD debugging information is stored in a single Section in the executable named .asd.
    • DWARP version 1.0
      When DWARF 1.0 debugging information is included by the linker in the ELF executable, the file contains the following ELF Sections, each of which has a Section Header Table entry:
      Section name Contents
      .debug debugging entries
      .line fileinfo entries
      .debug_pubnames table for accelerated access to debug items
      .debug_aranges address ranges for compilation units
    • DWARF version 2.0
      When DWARF 2.0 debugging information is included by the linker in the ELF executable, the file contains the following ELF sections, each of which has a Section Header Table entry:
      Section name Contents
      .debug_info debugging entries
      .debug_line fileinfo statement program
      .debug_pubnames table for accelerated access to debug items
      .debug_aranges address ranges for compilation units
      .debug_macinfo macro information (#define / #undef)
      .debug_frame call frame information
      .debugj_abbrev abbreviation table
      .debug_str debug string table

    关于DWARF调试标准详见:http://www.dwarfstd.org/。目前最新版本是The DWARF Debugging Standard Version 5

    Program Headers(程序头)

      可执行文件或者共享对象文件(Object File)的程序头部是一个结构数组,每个结构描述了一个段或者系统准备程序执行所必需的其它信息。对象文件(Object File)的"段"包含一个或者多个"节",也就是"段内容(Segment Contents)"。程序头部仅对于可执行文件和共享对象文件(Object File)有意义。
    图7 Program Header
    在这里插入图片描述
    程序头可以使用如下数据结构来表示(对应关系见注释):

    typedef struct {
    Elf32_Word    p_type;       // Type
    Elf32_Off     p_offset;     // Offset
    Elf32_Addr    p_vaddr;      // VirtAddr
    Elf32_Addr    p_paddr;      // PhyAddr
    Elf32_Word    p_filesz;     // FileSiz
    Elf32_Word    p_memsz;      // MemSiz
    Elf32_Word    p_flags;      // Flg
    Elf32_Word    p_align;      // Align
    } Elf32_Phdr;
    
    • p_type:这个成员告诉这个数组元素描述什么样的段,或者如何解释数组元素的信息。 类型值及其含义如下图所示。
      名称 取值 意义
      PT_NULL 0 数组元素未使用; 其他成员的值是未定义的。 此类型使程序头表已忽略条目。
      PT_LOAD 1 数组元素指定由p_filesz和p_memsz描述的可加载段。
      PT_DYNAMIC 2 数组元素指定动态链接信息。
      PT_INTERP 3 数组元素指定要作为解释器调用的以空值结尾的路径名的位置和大小。
      PT_NOTE 4 数组元素指定辅助信息的位置和大小。
      PT_SHLIB 5 该段类型是保留的,但具有未指定的语义。
      PT_PHDR 6 数组元素(如果存在)指定程序头表本身的位置和大小。
      PT_ARM_ARCHEXT 0x70000000 Platform architecture compatibility information
      PT_ARM_EXIDX
      PT_ARM_UNWIND
      0x70000001 Exception unwind tables
    • p_offset:此成员给出从文件头到该段第一个字节的偏移
    • p_vaddr:此成员给出段的第一个字节将被放到内存中的虚拟地址。
    • p_paddr:此成员仅用于与物理地址相关的系统中。因为 System V 忽略所有应用程序的物理地址信息,此字段对与可执行文件和共享对象文件(Object File)而言,具体内容是未指定的。
    • p_filesz:此成员给出段在文件镜像中所占的字节数。可以为 0。
    • p_memsz: 此成员给出段在内存镜像中占用的字节数。可以为 0。
    • p_flags:此成员给出与段相关的标志。
      名称 取值 意义
      PF_X 1 可执行的段
      PF_W 2 可写的段
      PF_R 4 可读的段
      PF_MASKPROC 0xf0000000 保留
    • p_align:可加载的进程段的 p_vaddr 和 p_offset 取值必须合适,相对于对页面大小的取模而言。此成员给出段在文件中和内存中如何 对齐。数值 0 和 1 表示不需要对齐。否则 p_align 应该是个 正整数,并且是 2 的幂次数,p_vaddr 和 p_offset 对 p_align 取模后应该相等。

    Symbol table(符号表)

      一个对象文件的符号表保存了定位和重定位所在程序的符号定义和引用所需的信息。符号表以数组的下标进行索引。0 指定表中的第一个条目,并用作未定义的符号索引。ARM 结构中,符号表与标准的 ELF 文件没有任何区别。

    图12 .o文件 Symbol table(部分)
    在这里插入图片描述
      在 C 语言中,符号表保存了程序实现或使用的所有全局变量和函数,如果程序引用一个自身代码未定义的符号,则称之为未定义符号,这类引用必须在静态链接期间用其他目标模块或库解决,或在加载时通过动态链接解决。

    符号表可以使用以下数据结构表示:

    typedef struct {
    Elf32_Word      st_name;    // Name
    Elf32_Addr      st_value;   // Value
    Elf32_Word      st_size;    // Size
    unsigned char   st_info;    //
    unsigned char   st_other;   
    Elf32_Half      st_shndx;   // Ndx
    } Elf32_Sym;
    
    • st_name:该成员将对象文件(Object File)的符号字符串表中的索引保存在符号名称的字符表示中
    • st_value:该成员给出相关联的符号的值。 根据上下文,这可能是绝对值,地址等等; 不同对象文件(Object File)类型的符号表条目对 st_value 成员的解释略有不同。
      • 在可重定位文件中,st_value 保持其索引为 SHN_COMMON 的符号的对齐约束。
      • 在可重定位文件中,st_value 包含已定义符号的节偏移量。 也就是说,st_value 是 st_shndx 标识的部分开头的偏移量。
      • 在可执行文件和共享对象文件中,st_value 包含虚拟地址 1。 为了使这些文件的符号对动态链接器更有用,段偏移(文件解释)让位于与段号无关的虚拟地址(存储器解释)。
    • st_size:许多符号具有相关尺寸。 例如,数据对象的大小是对象中包含的字节数。 如果符号没有大小或未知的大小,该成员将保持0。
    • st_info:该成员指定符号的类型和绑定属性。 值和值的列表如下面两个表格所示。 以下代码显示了如何操作这些值。
      #define ELF32_ST_BIND(i) ((i)>>4)
      
      #define ELF32_ST_TYPE(i) ((i)&0xf)
      
      #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
      
      A symbol’s binding determines the linkage visibility and behavior.
      Name Value Meaning
      STT_NOTYPE 0 The symbol’s type is not specified.
      STT_OBJECT 1 The symbol is associated with a data object, such as a variable, an array, and so on.
      STT_FUNC 2 The symbol is associated with a function or other executable code.
      STT_SECTION 3 The symbol is associated with a section. Symbol table entries of this type exist primarily for relocation and normally have STB_LOCAL binding.
      STT_FILE 4 A file symbol has STB_LOCAL binding, its section index is SHN_A BS, and it precedes the other STB_LOCAL symbols for the file, if it is present.
      STT_LOPROC 13 Values in this inclusive range are reserved for processor-specific semantics. If a symbol’s value refers to a specific location within a section, its section index member, st_shndx, holds an index into the section header table. As the section moves during relocation, the symbol’s value changes as well, and references to the symbol continue to point to the same location in the program. Some special section index values give other semantics.
      STT_HIPROC 15
      In each symbol table, all symbols with STB_LOCAL binding precede the weak and global symbols. A symbol’s type provides a general classification for the associated entity. Figure 3-17, Symbol Types, ELF32_ST_TYPE
      Name Value Meaning
      STT_NOTYPE 0 The symbol’s type is not specified.
      STT_OBJECT 1 The symbol is associated with a data object, such as a variable, an array, and so on.
      STT_FUNC 2 The symbol is associated with a function or other executable code.
      STT_SECTION 3 The symbol is associated with a section. Symbol table entries of this type exist primarily for relocation and normally have STB_LOCAL binding.
      STT_FILE 4 A file symbol has STB_LOCAL binding, its section index is SHN_A BS, and it precedes the other STB_LOCAL symbols for the file, if it is present.
      STT_LOPROC 13 Values in this inclusive range are reserved for processor-specific semantics. If a symbol’s value refers to a specific location within a section, its section index member, st_shndx, holds an index into the section header table. As the section moves during relocation, the symbol’s value changes as well, and references to the symbol continue to point to the same location in the program. Some special section index values give other semantics.
      STT_HIPROC 15
    • st_other:该成员目前只有 0,没有定义。
    • st_shndx:每个符号表条目与某些部分有关"定义"; 该成员保存相关部分标题表索引。 如上图3-7和3.3.1节所述,一些段索引表示特殊含义。

      The symbols in ELF object files convey specific information to the linker and loader. See section 4, ARM- and Thumb-Specific Definitions, for a description of the actual linking model used in the system.

    • SHN_ABS:The symbol has an absolute value that will not change because of relocation.
    • SHN_COMMON:The symbol labels a common block that has not yet been allocated. The symbol’s value gives alignment constraints, similar to a section’s sh_addralign member. That is, the link editor will allocate the storage for the symbol at an address that is a multiple of st_value. The symbol’s size tells how many bytes are required.
    • SHN_UNDEF:This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file’s references to the symbol will be linked to the actual definition.

    As mentioned above, the symbol table entry for index 0 (STN_UNDEF) is reserved. It is shown in Figure 3-18. Figure 3-18, Symbol Table Entry: Index 0

    Name Value Note
    st_name 0 No name
    st_value 0 Zero value
    st_size 0 No size
    st_info 0 No type, local binding
    st_other 0
    st_shndx SHN_UNDEF No section

    String table(字符串表)

      字符串表节包含以 NULL(ASCII 码 0)结尾的字符序列,通常称为字符串。ELF 对象文件(Object File)通常使用字符串来表示符号和节名称。对字符串的引用通常以字符串在字符 串表中的下标给出。ARM结构中,字符串表与标准的 ELF 文件没有任何区别。

    axf 文件

      axf 文件是 ARM 的调试文件,其格式符合上一节讲的对象文件(Object File)格式(ELF)。其中除了包含了完整的 bin 文件外,还附加了其他的调试信息。在调试的时候,这些调试信息是不必下到 RAM 中去的,真正下到 RAM 中的信息仅仅是可执行代码。下图为 axf 文件的头部。
    在这里插入图片描述
      通过直接查看完整的 axf 文件可以看出,axf 中绝大多数都是和调试相关的内容。真正的 Bin 只是其中的一小部分。Bin 的结尾处在 axf 文件中也很容易找到,再次就不在赘述。
      既然前面我们说了,axf 文件就是 ELF 文件格式,那么我们可以使用 readelf 工具,具体查看一下axf文件。下图是一个 axf 文件的节表
    在这里插入图片描述

    Bin文件

      bin 文件是 ARM 的可执行文件,是最纯粹的二进制机器代码。与 HEX 文件包括地址信息的不同,BIN 文件格式只包括了数据本身。在烧写或下载 HEX 文件的时候,一般都不需要用户指定地址,因为 HEX 文件内部的信息已经包括了地址。而烧写 BIN 文件的时候,用户是一定需要指定地址信息的。
      ARM 的 Bin 文件就是 axf 的精华部分(掐掉ELF头,去掉 .symtab、.debug和.symtab区里的信息)。下图是笔者使用 Winhex 截取的 ARM 的 Bin 文件的开头和结尾的示意图。
    在这里插入图片描述

    hex 文件

      首先,hex 文件最初由 Intel 提出。在 Intel HEX 文件中,每一行是一个 HEX 记录,由十六进制数组成的机器码或者数据常量,Intel HEX 文件经常被用于将程序或数据传输存储到 ROM、EPROM,大多数编程器和模拟器使用 Intel HEX 文件。
      hex 文件全部由可打印的 ASCII 字符组成。如下图就是 ARM-MDK5.22 生成的一个hex文件(部分)
    在这里插入图片描述
    从上图不难看出,hex 文件就是一个个的十六进制的字符串。实际上,一个 Intel HEX 文件可以包含任意多的十六进制记录,每条记录有五个域,每条记录都由一个冒号":"打头。一个数据记录以一个回车和一个换行结束。其格式如下:
    :CCAAAARR[DD...]ZZ
    其中:

    • CC:本条记录中数据(dd)的字节数目
    • AAAA:本条记录中的数据在存储区中的起始地址
    • RR:记录类型:
      • 00 数据记录 (data record)
      • 01 文件结束记录 (end record)
      • 02 扩展段地址记录 (paragraph record)
      • 03 扩展线性地址记录 (transfer address record)
    • DD… :数据域。表示一个字节的数据,一个记录可能有多个数据字节,字节数目可以 查看ll域的说明
    • ZZ:效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有字母对所表示的十六进制数字都加起来然后模除 256 得到的余数最后求出余数的补码即是本效验字节 cc。

    举例如下:
    :10400000781A00203D420008034C0008D14B0008FC

    • 10: 长度 16
    • 4000: 起始地址
    • 00: 表示数据记录
    • 78 ~ 08: 数据
    • FC:校验和

    参考

    1. Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification Version 1.2
    2. ARM® Compiler v5.06 for µVision® Version 5 armlink User Guide
    3. ARM® Compiler v5.06 for µVision® Version 5 armcc User Guide
    4. ARM ELF File Format ARM DUI 00101-A
    5. ARM ELF Development Systems Business Unit Engineering Software Group
    6. ELF for the ARM® Architecture

    下载 相关文档的 PDF 文档

    展开全文
  • C/C++ ShellExecuteEx调用exe可执行文件

    千次阅读 2015-11-02 20:55:30
    C/C++ ShellExecuteEx函数调用可执行文件exe


    本系列文章由 @YhL_Leo 出品,转载请注明出处。
    文章链接: http://blog.csdn.net/yhl_leo/article/details/49591995


    以商业的软件Enblend为例,进行图像无缝拼接和匀光匀色,可以如下直接在Dos中使用命令行调用:

    C:\...\Test> enblend -o blend.tif 0.tif 1.tif 2.tif 3.tif 4.tif

    输入数据:

    Input

    输出结果:

    Output

    C/C++中,有几种方法可以直接调用可执行文件exe,这里以最常用的ShellExcecuteEx函数为例。上面使用命令行操作,可转化为:

    // ShellExcecuteEx call the Enblend.exe 
    
    #include <windows.h>
    #include <shellapi.h>
    #include <stdio.h>
    #include <tchar.h>
    
    void main()
    {
        SHELLEXECUTEINFO shExecInfo = {0};
        shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        shExecInfo.fMask  = SEE_MASK_NOCLOSEPROCESS;
        shExecInfo.hwnd   = NULL;
        shExecInfo.lpVerb = _T("open");
        shExecInfo.lpFile = _T("C:\\Users\\Leo\\Desktop\\Test\\enblend.exe");
        shExecInfo.lpParameters = _T("-o blend.tif 0.tif 1.tif 2.tif 3.tif 4.tif");
        shExecInfo.lpDirectory  = _T("C:\\Users\\Leo\\Desktop\\Test");
        shExecInfo.nShow        = SW_SHOW;
        shExecInfo.hInstApp     = NULL;
        ShellExecuteEx(&shExecInfo);
        WaitForSingleObject(shExecInfo.hProcess,INFINITE);
    }

    两者的运行结果是完全一样的。如果编译遇到BUG:cannot convert from 'const char [7]' to 'LPCWSTR',请见博客Multi-Byte Character Set & Unicode Character Set

    对于ShellExcecuteEx函数,感兴趣的可以阅读以下两篇文章:

    除此外,C/C++中调用可执行exe文件的方法还有:

    • system函数
    • exec或者execv函数
    • WinExec函数
    • CreateProcess函数

    详细请阅读:

    展开全文
  • Matlab +GUI+数据库+可执行文件

    千次阅读 2018-10-15 18:55:50
    Matlab +GUI+数据库+可执行文件 目的:Matlabl通过GUI界面输入数据库筛选条件,取出数据库数据作图,并生成可执行文件文件 一、Matlab GUI设计 方法:命令行输入guide,选择blank GUI,后弹出以下界面,可根据需求...
  • python代码直接生成可执行exe文件

    千次阅读 多人点赞 2019-11-11 19:11:02
    python中有一个很厉害的库可以直接将写好的python代码打包成可执行的.exe文件,生成好的文件不需要python运行环境和pycharm等IDE就可以直接双击运行,是不是很厉害呢!这样你就可以开发一些简单的小游戏直接发给你的...
  • Python读取sql文件,且可执行

    万次阅读 2019-05-17 17:44:43
    python 直接读取 sql 文件,达到使用 read_sql 可执行的目的
  • 从C文件可执行elf文件

    千次阅读 2013-09-24 15:01:14
    摘要:本文主要为你解释一个C文件是如何被一步步处理成可执行的elf格式文件的。 本文来源: 从C文件到ELF  说明:所有本文的用例是以下hello.c程序: #include int main(int argc, char *argv[]) { printf(...
  • linux可执行文件格式

    万次阅读 2017-05-24 23:27:05
    1. 可执行文件的任务: 可执 行文件的创建: 编译(compile): 源程序文件被编译成目标文件, 连接(link): 多个目标文件 被连接成一个最终的可执行文件可执行文件的运行: 可执行文件被加载(load)到内存中执行。...
  • QT 寻找可执行文件的依赖文件

    千次阅读 2018-02-09 20:23:03
    使用c++ qt编译出来的文件,单独拿出来放到一台没有安装QT环境的计算机中,一般...但是这些依赖文件程序找不到,那么怎么寻找QT可执行程序的依赖文件呢?这里一般包含两部分,一部分为系统依赖文件,另一部分为程序...
  • 我们的源代码通过预处理,编译,汇编,链接后形成可执行文件,(关于源代码到可执行文件的介绍见我的另一篇博客:程序从代码到可执行文件的过程简述)那么当我们在cmd窗口敲出指令$test argv1 argv2\n 后,操作系统...
  • linux下编译c文件成为可执行文件的实例和详细过程

    万次阅读 多人点赞 2019-06-18 13:49:10
    三、执行 四、编译的四个步骤 一、准备C文件 在命令行模式下输入:vim hello.c 进入编辑模式,输入以下代码: #include<stdio.h> int main(void){ printf("Hello World!\n"); return 0; } 首先点击...
  • Pycharm生成可执行文件.exe

    万次阅读 多人点赞 2019-01-20 18:40:59
    一个项目开发完毕后总有一想法,就是生成可执行文件,总不能一直用python xxx执行吧。 以下操作同时适用于windows和Linux下的Pycharm(我在Ubuntu下试验过,生成的是在Ubuntu下的可执行文件) 1、打开Pycharm。 2...
  • go语言生成可执行文件

    千次阅读 2019-06-25 15:54:25
    go语言如何生成可执行文件
  • 上传文件到linux主机后,如果需要执行上传的文件,需要修改文件的权限。否则会弹出提示:permission denied。 更改权限的命令是chomd chmod的语法格式如下: chmod [who] [opt] [mode] 文件/目录名 其中who表示...
  • Android 编译静态链接的可执行文件

    千次阅读 2016-07-13 23:18:53
    Android 编译静态链接的可执行文件在Android 开发与调试过程中往往遇到以下场景,导致我们编译的可执行程序无法运行: 不支持动态链接,比如系统初始化进程init和Recovery模式下执行的recovery可执行程序,它们...
  • 但是,编译成功,与可执行文件可以运行(即使代码都是正确的)是两件事,虽然,往往编译成功,可执行文件就可以运行。 在命令行中,输入可执行文件的命令: 首先先要做地址映射,将代码段和数据段分别映射到...
  • MATLAB生成可执行文件(.exe文件)

    万次阅读 2015-10-24 13:51:23
    将M文件编译为独立可执行文件的语法是: >>mcc –m fun1.m fun2.m….. 其中fun1就是最后的可执行文件的名称。
  • Linux 可执行文件结构与进程结构

    千次阅读 多人点赞 2015-04-19 10:15:38
    在 Linux 下,程序是一个普通的可执行文件以下列出一个二进制可执行文件的基本情况: 可以看出,此可执行文件在存储时(没有调入到内容)分为代码区(text)、数据区(data)和未初始化数据区(bss)3 个部分。...
  • 一个可执行文件是怎么来的

    千次阅读 2015-11-02 09:35:55
    一个可执行文件的生成一般都要经过下面几个步骤: 编辑 、预处理 、 编译、优化、汇编 、 连接 ——>可执行文件 下面将从这几个步骤一个一个来分析他们的具体内容。 1. 编辑 编辑这个过程其实挺简单的,但也是最...
  • 通过进程句柄,获得可执行文件的路径,主要有以下方法: 第一方法:也是最常用的方法,是通过GetModuleFileNameEx函数获得可执行文件的模块路径,这个函数从Windows NT 4.0开始到现在的Vista系统都能使用,向...
  • 如何将Python写的代码打包成.exe可执行文件

    万次阅读 多人点赞 2021-05-10 19:55:06
    以下将讲解Python代码如何打包成.exe文件。 1. 下载pyinstaller 因为Python中有很多三方包,我们想要这些三方包也包含在里面就需要一个工具,就是pyinstaller,很简单,直接在命令行输入pip install pyinstaller ...
  • .py文件转换成exe可执行文件

    千次阅读 2019-05-06 23:31:14
    管理员打开cmd,并且复制.py文件到Pyinstaller文件夹中(与pyinstaller.py同一层文件夹下),之后把路径切换到当前路径打开命令提示行,输入以下内容(xxx.py是文件名): python pyinstaller.py -F xxx.py 2、pip...
  • MATLAB+GUI 生成可执行exe文件

    万次阅读 多人点赞 2019-05-07 12:28:01
    那么恭喜你,在生成可执行文件之前,你需要先搞定编译器的问题。 解决方案 下载 MinGW-64 C/C++ 编译器 倘若你用的是正版MATLAB,那么按照提示点进链接下载安装即可。 倘若你跟我一样,用的不知道哪里下载的破解.....
  • 在DevC++中新建项目consol ...编写以下程序: //main.cpp #include <iostream> #include "func1.h" #include "func2.h" using namespace std; /* run this program using the console pauser or add your o...
  • 在Linux下用sh打包发布可执行文件

    千次阅读 2019-03-02 20:09:14
    我们在linux下编写代码时,会用到一些额外的库(动态或者静态),如小编在qt下写opencv的程序,是在电脑上,项目需求,需要将其移植到嵌入式板子上。...1.利用qt生成可执行文件,使用release的方式编译出可执行...
  • 刚刚创建的一个脚本,没有办法执行,需要进行执行的权限。 那么这里首先要学习linux如何更改权限了,命令就是chmod了。 chmod的语法格式如下: chmod [who] [opt] [mode] 文件/目录名 其中who表示对象,是以下...
  • 一个项目开发完毕后总有一想法,就是生成可执行文件,总不能一直用python xxx执行吧。 以下操作同时适用于windows和Linux下的Pycharm(我在Ubuntu下试验过,生成的是在Ubuntu下的可执行文件) 1、打开Pycharm。 2...
  • Python程序打包成exe可执行文件

    万次阅读 多人点赞 2017-08-02 16:04:20
    Python是一个脚本语言,被解释器解释执行。它的发布方式: .py文件:对于开源项目或者源码没那么重要的,直接提供源码,需要使用者自行安装Python并且安装依赖的各种库。(Python官方的各种安装包就是这样做的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,333,883
精华内容 533,553
关键字:

下列哪种文件是可执行文件