前言:
问题:最后编译出来的可执行文件里面是什么?除了机器码还有什么?他们怎么存放的?怎么组织的?
在Linux系统中可执行文件属于elf文件格式中的一种,它里面有编译后的机器指令,数据,符号表,调试信息,字符串等等信息。如果要知道它是如何存放的,那就需要了解ELF文件格式
可执行程序:
可执行文件格式( Executable)主要是 Windows下 的 PE (Portable Executable)和 Linux 的 ELF (Executable Linkable Format),它们都是 COFF (Common file formal)格式的变种。目标文件就是源代码编译后但未进行链接的那些中间文件(Windows 的 .obj和 Linux下的.o)它跟可执行文件的内容与结构很相似,所以一般跟可执行文件格式一起采用同一种格式存储。从广义上看, 目标标文件与可执行文件的格式其实几乎是一样的,所以我们可以广义地将目标文件与吋执行文件看成是一种类型的文件,在 Windows下,我们 可以统称它们为 PE-COFF文件格式。在 Linux下,我们可以将它们统称为 ELF文件。其他不太常见的可执行文件格式还有Intel/Microsoft的OMF(Object Module Format)、Unix a.out 格式和MS-DOS .COM格式等。
不光是可执行文件(Windows的.exe和Linux下的ELF可执行文件)按照可执行文件 格式存储。动态链接库(DLL,Dynamic Linking Library) (Windows 的.dll 和 Linux 的.so) 及静态链接库(Static Linking Library) (Windows的.lib和Linux的.a)文件都按照可执行文件格式存储。它们在Windows K都按照PE-COFF格式存储,Linux下按照ELF格式存储。 静态链接库稍有不同,它是把很多目标文件捆绑在一起形成一个文件,再加上一些索引,你可以简单地把它理解为一个包含有很多目标文件的文件包。ELF文件标准里面把系统中采用
ELF文件格式的文件归为下面所列的四类。
上面四种文件,都可以统称为编译的目标文件,它们都是通过编译得到的产物。它里面有编译后的机器指令,数据,符号表,调试信息,字符串等等信息,它们按节存储,也可以说是按段存储。下图可以查看程序与目标文件的示意图
对照上图,一般C语言的编译后执行语句都编译成机器代码,保存在. text段;己初始化的全局变量和局部静态变最都保存在. data段:未初始化的全局变最和局部静态变量一般放在一个叫. “bss”的段里。我们知道未初始化的全局变量和局部静态变最默认值都为 0,本来它们也可以被放在. data段的,但是因为它们都是0,所以为它们在. data段分配空间并且存放数据0是没有必要的。程序运行的时候它们的确是要占内存空间的,并且可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小总和记为.bss段。所以.bss段只是为未初始化的全局变量和局部静态变量预留位置而己,它并没有内容,所以它在文件中也不占椐空间。
ELF文件
ELF文件类型:
- 可重定位文件:用户和其他目标文件一起创建可执行文件或者共享目标文件,例如lib*.a文件。
- 可执行文件:用于生成进程映像,载入内存执行,例如编译好的可执行文件a.out。
- 共享目标文件:用于和其他共享目标文件或者可重定位文件一起生成elf目标文件或者和执行文件一起创建进程映像,例如lib*.so文件。
ELF文件作用:
ELF文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),所以可以从不同的角度来看待elf格式的文件:
- 如果用于编译和链接(可重定位文件),则编译器和链接器将把elf文件看作是节头表描述的节的集合,程序头表可选。
- 如果用于加载执行(可执行文件),则加载器则将把elf文件看作是程序头表描述的段的集合,一个段可能包含多个节,节头表可选。
- 如果是共享文件,则两者都含有。
ELF文件总体组成:
elf文件头描述elf文件的总体信息。包括:系统相关,类型相关,加载相关,链接相关。
- 系统相关表示:elf文件标识的魔术数,以及硬件和平台等相关信息,增加了elf文件的移植性,使交叉编译成为可能。
- 类型相关就是前面说的那个类型。
- 加载相关:包括程序头表相关信息。
- 链接相关:节头表相关信息
ELF文件结构:
整个ELF文件结构图如下:
实际的ELF文件结构,除了我们上面提到的常见的数据段,代码段,bss段外,它还包含了其他的一些段。如下图:
ELF结构信息查看
在Linux 系统中,如果要查看ELF文件里面的信息,可以使用命令readelf 命令查看
-a
--all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I.
-h
--file-header 显示elf文件开始的文件头信息.
-l
--program-headers
--segments 显示程序头(段头)信息(如果有的话)。
-S
--section-headers
--sections 显示节头信息(如果有的话)。
-g
--section-groups 显示节组信息(如果有的话)。
-t
--section-details 显示节的详细信息(-S的)。
-s
--syms
--symbols 显示符号表段中的项(如果有的话)。
-e
--headers 显示全部头信息,等价于: -h -l -S
-n
--notes 显示note段(内核注释)的信息。
-r
--relocs 显示可重定位段的信息。
-u
--unwind 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。
-d
--dynamic 显示动态段的信息。
-V
--version-info 显示版本段的信息。
-A
--arch-specific 显示CPU构架信息。
-D
--use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段。
-x <number or name>
--hex-dump=<number or name> 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。
-w[liaprmfFsoR] or
--debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示调试段中指定的内容。
-I
--histogram 显示符号的时候,显示bucket list长度的柱状图。
-v
--version 显示readelf的版本信息。
-H
--help 显示readelf所支持的命令行选项。
-W
--wide 宽行输出。
@file 可以将选项集中到一个文件中,然后使用这个@file选项载入
引用:
https://man.linuxde.net/readelf
---------------------------------------2022.08.21日更新---------------------------------------
由于各种原因,本博客将不再更新,
新的文章内容和附件工程文件
可以通过面的方式获取:
|微|·-·|信|·==·|公|·-·|众|·-·|号|:liwen01
也可以通过博客主页信息进行获取
感恩您的关注,谢谢~