明确一点,什么可以叫可执行文件。从广义上来讲,文件中的数据是可执行的代码,这样的文件壳称为可执行文件,像一些.out、.exe、.sh、.py文件。从狭义上讲,文件中的数据是机器码的文件,像.out、.exe、.dll、.so文件。
可执行文件分类
-
Windows:PE(Protable Executable)
- 可执行程序.exe
- 动态链接库.dll
- 静态链接库.lib
-
Linux:ELF(Executable and Linkable Format)
-
可执行程序.out
-
动态链接库.so
-
静态链接库.a
注意windows以后缀名识别文件
linux以文件头识别文件,用file命令查看文件格式
[root@VM-8-5-centos ~]# file a.out a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=f745fbc7e2ea1f4aa6f74525a787b0ddc3fb48e6, not stripped
-
ELF文件格式
![](https://damoxilai.github.io/post-images/1628042262663.png)
-
ELF头
ELF头必须在文件开头,记录ELF文件基本信息、组织结构。
ELF头包括ELF的magic code、程序运行的计算机架构、程序入口等内容,可以通过“readelf -h ”命令读取其内容,一般用于找到一些程序的入口
![](https://damoxilai.github.io/post-images/1628042273908.png)
解析ELF文件头的目的是确定程序的入口指令集架构、ABI版本等系统是否支持的信息,以及读取程序的入口。
-
程序头表/段表
解析程序头表是为了确定需要加载的程序、告诉系统如何创建进程。程序头表就是一个程序头的结构体数组,其每项都包含这个段的描述信息。操作系统执行程序时按照指定的短信息将ELF文件的指定内容加载到内存的指定位置。
每个程序头的内容主要包括段类型、其在ELF文件的地址、加载到内存中的哪个地址、段长度、内存读写属性。
存放代码的段内为可读可运行,存放数据段则可读可写或者只读。
-
节头表
节和段是ELF文件描述同一段数据的两种不同形式
描述节的各种信息数据统一存放在节头表中
- .text节——存放一个程序的运行所需的所有代码
- .rdata节——存放程序使用到的不可修改的静态数据,如字符串等
- .data节——存放程序可修改的数据,如C语言中已经初始化的全局变量
- .bss节——用于存放程序的可修改数据,与.data不同的是,这些数据没有被初始化,所以没有占用ELF空间。虽然节头表中存在.bss节,单文件中并没有对应的数据。程序开始执行后,系统才会申请一块空间来做实际的.bss节
- .plt节和.got节——程序调用动态链接库(so文件)中函数时,需要这两个函数配合以获取被调用的函数地址
段(segment)与节(section)
磁盘中的ELF(可执行文件)与内存中的ELF(进程内存映像)
- 段视图用于进程内存区域的rwx权限划分
- 节视图用于ELF文件编译连接时与在磁盘上存储时的文件结构的组织
- 一个段包含多个节
- 代码段包含了代码与只读数据
- .text节、.rodata节、.hash节、.dynsym节、.dynstr节、.plt节、.reg.got节
- 数据段包含了可读可写数据
- .data节、.dynamic节、.got节、.got.plt节、.bss节
- 代码段包含了代码与只读数据