Yet Another Guide to Linking and Loading ELF Files

 

阅读本文中文版

前置知识

阅读本文需要读者具备:

  • 了解C语言项目的编译分为预处理-编译-汇编-链接过程。能使用gcc/clang编译简单的C语言项目。
  • 了解ELF文件的组成部分,知道ELF静态库和动态库的概念。
  • 了解位置无关代码的概念,知道使用PC相对定位是实现位置无关代码的一种基本方法。

前言

链接和动态链接,是ELF文件格式体系中实现代码模块化和可复用的关键环节。从最宏观的概念上来说,它们是很简单的,链接将许多不同的输入文件组合到一起,形成一个独立的可执行文件或动态库。而动态链接则允许多个不同的进程共享同一份代码和数据,从而减少内存资源使用。但是,为了兼容不同架构与平台,适应不同的应用场景,在ELF链接和动态链接过程中,我们就会面临着许多较为细节的问题;而对这些问题的针对性解决方案,是ELF链接和动态链接的复杂性的主要来源之一。所幸,gcc和clang等编译器驱动(compiler drivers)所提供的默认设置和命令行参数语法,已经具有相当的泛用性,对于许多项目而言,开发者无需深入去理解链接和动态链接过程的各种细节以及背后的设计思路。然而,一旦遇到与链接和动态链接相关的问题,我们常常会发现可供参考的资料很少,甚至在Google上搜索关键词后就直接跳转到了gcc/LLVM等项目的bug tracker中,对于没有相关领域背景的开发者而言,这些搜索结果几乎无法提供足够的解决问题的信息;某些情况下,即使最终解决了问题,也并未理解其根本原因,今后遇到类似的问题时又需要花费相当的时间。

在几个月前,笔者涉及了多个和ELF强相关的项目,其中也遇到了多个和链接相关的问题,一些问题的现象与链接无关,但在仔细分析后,发现问题的根源也在于链接。当时,笔者对于ELF链接与动态链接的认识仅限于《深入理解计算机系统》一书中的简要介绍,比较粗浅,花费了许多时间查找资料才得以解决这些问题。在查找资料的过程中,笔者读到了多篇由@MaskRay 撰写的文章,他的文章提供了大量对于ELF链接和动态链接过程中的特定主题的深入分析,讨论了ELF链接和动态链接过程中的诸多细节,以及它们所要解决的问题与设计原则。受他文章的启发,笔者在完成上述项目后,就希望对ELF链接和动态链接过程做一个比较系统性的研究,本文就是笔者研究的总结。在本文中,笔者尝试从位置相关可执行文件/位置无关可执行文件/动态库这三种ELF文件类型所基于的不同假设出发,探讨由此衍生的大量细节问题,以及ELF是如何针对这些问题提出相应解决方案的;同时,本文尝试将与ELF链接和动态链接相关的庞杂内容组织成一个体系,以期帮助读者全面地理解ELF链接和动态链接,构建一种较为系统的思维方式,最终能有助于读者针对自己的需求选择合适的链接和动态链接参数、高效地解决相关的问题。

在行文上,本文力求做到以下几点:

  • 问题导向。在介绍具体的细节前,笔者力求总是先提出一个实际的问题,从对问题的分析和理解开始,逐步引入所要介绍的内容。也希望读者相较于具体的细节,更重要的是把握所要解决的问题,从而有助于读者运用本文所介绍的知识去分析和解决今后所遇到的相关问题。
  • 逻辑连贯。本文对于ELF链接和动态链接中的诸多话题都做了比较深入的分析,因而难以避免地会有一些大段的分析性文字。在撰写这些内容时,笔者尽可能确保下一句总是承接上一句的问题,或是进一步阐述上一句中所得到的结论,以期带给读者较为连贯的阅读体验。同时,笔者在研究过程中也提出了许多问题,这些问题中较有讨论价值的部分也放到了本文中,以进一步增强行文逻辑的自洽性,并尽可能地解决读者在阅读本文的过程中可能遇到的问题。
  • 分析设计原则。对于文中提到的许多细节,笔者尝试基于自己对整个ELF链接和动态链接过程的理解,以及所能找到的在引入此细节时的原始讨论(issues或邮件等),分析其背后的设计原则和思路,希望有助于读者理解和运用这些设计思路,解决自己所遇到的实际问题或是设计特定的解决方案。

由于笔者能力和研究时间有限,本文也存在一些主要的不足之处:

  • 所介绍的内容主要局限于C语言、gcc/clang编译器驱动,x86_64和aarch64架构。
  • 可能存在一定的细节问题或理解错误之处。本文中的部分内容由于笔者未能在相关标准中找到权威的阐述,系笔者基于自己对ELF链接和动态链接的整体理解所作出的分析和阐述,难免会有所误解甚至错误。但本文的总体框架应当是相对比较完备的。
  • 篇幅较长,全文约5万字左右,需要花费相当的时间阅读。后续笔者会尝试将本文拆分到多个章节文件中,以降低单次阅读的所需时间,也希望笔者在行文上的考虑能尽可能降低读者的阅读难度。

如果读者在阅读过程中发现了问题,欢迎通过本项目issue与笔者进行交流,也欢迎通过PR等方式对本文提出修改意见,笔者在此预先感谢您的贡献!

致谢

本文的完成必须感谢@MaskRay 对于ELF格式、编译、链接与动态链接撰写的一系列极具深度和综合性的文章,以及他对LLVM等项目的卓越贡献。他的一系列文章启发了笔者对于ELF链接与动态链接这一主题的探索、理解与研究。在他的文章中,笔者首次从对链接一知半解的状态,认识到了符号是否具有可抢占性将会对整个链接过程带来极为深远的影响,进而从这一点出发对ELF链接做了一个较为系统的分析和研究。他的文章也汇集了众多权威的参考资料,这些资料为笔者提供了大量基础知识,让笔者逐渐从阅读他的文章时“两眼一抹黑”过渡到能较为准确理解他文章中涉及到的每一个问题。本文的许多内容也直接来源于笔者在阅读他的相关文章后的分析、印证与思考。可以说,没有他所做的一系列开创性工作,就不会有本文的诞生。