可执行二进制文件
作者:互联网
一、格式
一份 C 代码经过编译后,可以生成能直接运行的二进制文件,在不同操作系统上这些二进制文件有不同的特征,在 Windows 上通常后缀为 .exe,在 Linux 上通常没有后缀。除此之外,这些二进制文件在内部数据的组织和结构上也有很大的区别,针对 Windows 的有 PE 格式,类 Unix 系统的有 elf 格式。
1.ELF 格式
不同可执行文件的数据组织和结构虽然不同,但它们对数据的基本组织方式都符合这样一个特征:使用统一的头部来保存可执行文件的基本信息,而其他数据则按照功能被划分在了以 section 或 segment 形式组织的一系列单元中。通过 file 命令可以看出这是一个共享目标文件,老版 gcc 生成的是可执行文件,新版默认启用 PIE 功能,让程序可以在任意地址加载,减少了系统攻击的风险,所以现在生成的是共享目标文件:
可以看出,它确实开了 pie:
2.ELF头
readelf 命令可以查看可执行文件的内部组成结构,用来获取可执行文件的信息,比如 readlf -h:
魔数第一个字节固定为 0x7f;二到三字节表示 ELF 的 ASCII 码;第五个字节表示操作系统位数,0x1表示 32 位,0x2 表示 64 位;第六个字节表示字节序;第七个字节表示版本号。Data 字段是数据存储形式,可以看出它是小端存储模式;Entry point address 是程序的入口地址,也就是执行程序时执行的第一条指令的地址。
3.ELF section头
通过 readelf -S 命令获取 ELF 文件头的信息,-E 表示按照一定规则扩展,-A 表示显示找到的数据的前一行和后一行:
上图所示的四个段分别是代码段,只读数据段,数据段(存放已初始化的全局变量),.bss 存放未初始化的全局变量或局部变量。可以通过 objdump 来验证:
可以看出 09f0 确实存放了右图代码中的只读数据,同理可以看到初始化的全局变量,也就是 .data 的值,左图是十六进制,0x14 对应右图的 20:
在 ELF 格式中,这些 section 组成了组成了描述该 ELF 文件内容的静态视图,而静态视图的重要作用是完成链接,链接将不同的类型的 ELF 文件相互整合,并最终生成可执行文件。
4.ELF Program头
除了由 section 组成的静态视图外,还有很多 secment 组成了组成了描述可执行文件的动态视图。segment 指定了应用程序在实际运行时,应如何在进程的 VAS 内部组织数据,可以通过 readelf -l 命令显示可执行文件的 segment 情况,这个命令显示出的第一部分是各个 segment 的信息:
第二部分显示了 segment 和 section 的对应关系,其中第三个 segment 对应了 .text 和 .rodata 等 section ,第四个 segment 对应了 .data 和 .bss 等 section:
segment 对应的头叫做 program 头,其中包含各个 segment 的类型、偏移地址、对齐情况等信息。LOAD 类型的 segment 在程序运行时会真正被载入到进程的 VAS 中,其余的 segment 主要用于辅助程序的正常运行(比如进行动态链接)。
关于 elf 文件格式的更多信息可以参考这个文档 和 Linux 手册。
5.ELF文件类型
ELF 作为一种文件格式,可以被四种类型的文件使用,分别是可重定位文件、可执行文件、共享目标文件和核心转储文件,如下图所示:
这四种 ELF 文件类型,虽然名称各不相同,但其内部的数据组织方式都遵循同样的 ELF 文件格式标准。由于功能不同,所以内部的组成有些差异。
1.比如可重定位文件,也就是 .o 文件,用于大型项目的增量式开发。将一些功能代码编译成一个可重定位文件,需要这个功能的程序只需要链接这个可重定位文件就可以实现这些功能了,这样做的好处是当这些功能发生变化时,可以只编译功能发生变化的代码。可重定位文件只有 section 的相关信息,没有 Program 头等用于支持运行的 ELF 结构,因此该类型的文件无法直接运行。需要经过静态链接生成含有 Program 头的可执行文件。
标签:可执行文件,文件,字节,二进制,section,ELF,执行,segment 来源: https://www.cnblogs.com/shuijiaoa/p/15944133.html