我一直在这里阅读 ELF 标准。据我了解,每个 ELF 都包含 ELF 头、程序头(为什么不止一个?)和节头。谁能解释一下:
或者,有人有更友好的 ELF 文档的链接吗?
ELF文件是如何生成的?这是编译器的责任吗?
它们可以由编译器、汇编器或任何其他可以生成它们的工具生成。即使是您自己编写的用于生成 ELF 文件的程序;)它们毕竟只是字节流,因此只需以二进制模式将字节写入文件即可生成它们。你也可以那样做。
什么是部分以及为什么我们需要它们?
ELF 文件分为多个部分。节是文件中最小的连续区域。您可以将它们视为管理器中的页面,每个页面都有自己的名称和类型来描述其内部包含的内容。链接器使用此信息,通过合并相同类型的部分(如果愿意,可以将页面粘合在一起),将来自不同模块的程序的不同部分组合到一个可执行文件或库中。
在可执行文件中,节是可选的,但它们通常用于描述文件中的内容、文件从哪里开始以及需要多少字节。
什么是程序头以及为什么我们需要它们?
它们主要用于制作可执行文件。为了运行程序,仅使用节是不够的,因为您不仅必须指定文件中的内容,还必须指定在运行过程中应将其加载到内存中的位置。程序头就是为了这个目的:它们描述段,这些段是正在运行的进程中的内存区域,具有不同的访问权限和内容。
每个程序头描述一个段。它告诉加载器应该将文件中的某个区域加载到内存中的哪个位置以及应该为该区域设置什么权限(例如,是否应该允许从中执行代码?应该是可写的还是只读的?)
段可以进一步细分为多个部分。例如,如果您必须指定将代码段进一步细分为程序显示的消息的代码和静态只读字符串。或者你的数据段被细分为时髦数据和硬核数据:J 这是由你决定的。
在可执行文件中,节是可选的,但拥有它们很好,因为它们描述了文件中的内容并允许转储文件的选定部分(例如使用工具objdump)。但有时需要它们来存储动态链接信息、符号表、调试信息等。
p_vaddr在程序头中,字段和的含义是什么p_paddr?
这些是将加载文件中的数据的地址。它们将文件的内容映射到相应的内存位置。第一个是虚拟地址,第二个是物理地址。
物理地址是“原始”内存地址。在现代操作系统上,这些不再在用户空间中使用。相反,用户态程序使用虚拟地址。操作系统欺骗用户态程序,让其相信它单独存在于内存中,并且整个地址空间都可供它使用。在幕后,操作系统将这些虚拟地址映射到实际内存中的物理地址,并且对程序透明地执行此操作。
当然,虚拟地址空间中的每个地址并非同时可用。实际可用的物理内存存在限制。因此操作系统只是将内存映射到程序实际使用的段(这里是 ELF 文件程序头中的“段”部分发挥作用的地方)。如果进程尝试访问某些未映射的内存,操作系统就会介入并说:“对不起,小伙子,该内存不属于您”。(程序可以寻址它,但无法访问它。)
每个部分都有自己的部分标题吗?
是的。如果节头表中没有条目,则它不是节:q 因为它们判断文件的某些部分是否是节的唯一方法是查看节头表,该表告诉您哪些节在文件中定义以及您可以在哪里找到它们。
您可以将节标题表视为书中的目录。没有目录,根本就没有任何章节,因为它们没有在任何地方列出。这本书可能有标题,但内容没有细分为可以通过目录找到的逻辑章节。ELF 文件中的部分也是如此:可能存在某些数据区域,但如果没有“目录”(即 SHT),您就无法分辨。