【Linux篇】ELF文件及其加载与动态链接机制

news2025/4/16 14:32:39

ELF文件及其加载与动态链接机制

  • 一. EFL文件
    • 1.1 ELF文件结构
    • 二. ELF文件形成与加载
    • 2.1 ELF形成可执行
    • 2.2 ELF控制性文件的加载
      • 2.2.1总结
  • 三. ELF加载与进程地址空间
    • 3.1 动态链接与动态库加载
      • 3.1.1 进程如何看到动态库
    • 3.2 全局偏移量表GOT(global offset table)
      • 3.2.1 函数调用
    • 3.2.2 GOT与动态链接的关系
  • 四. 最后

一. EFL文件

ELF文件可以是可执行文件、共享库文件、目标文件或核心转储文件(core dump)。

可执行文件(Executable File)

  1. 可执行文件是包含程序代码的ELF文件,经过编译和链接后可以直接执行。它通常包含程序的入口点,操作系统加载它后便开始执行。
  2. 这类文件可以通过命令行直接运行。例如,执行一个ls命令的二进制文件就是一个可执行的ELF文件。
  3. 文件的类型标识通常是ET_EXEC。

目标文件(Object File)

  1. 目标文件是源代码编译后生成的中间文件,它包含了程序的机器代码,但还没有完全链接。目标文件通常不能单独运行,需要与其他目标文件或者库文件一起链接,生成可执行文件。
  2. 文件的类型标识通常是ET_REL(Relocatable)。
  3. 目标文件会包含符号表、重定位信息和调试信息,供链接器使用。

共享库文件(Shared Library)

  1. 共享库文件是一种可以被多个程序同时使用的动态链接库(.so文件)。它包含了供多个程序共享的函数和代码,通常用于提供一些常见功能的共享实现。
  2. 当一个程序需要某些功能时,它会在运行时加载共享库,而不是在编译时将这些功能静态链接进程序。共享库有助于节省内存和磁盘空间。
  3. 文件的类型标识通常是ET_DYN(Dynamic)。

1.1 ELF文件结构

ELF文件的主要结构部分包括:

  1. 文件头(ELF Header):描述文件的基本信息,如文件类型、机器架构等。
  2. 节区头表(Section Header Table):描述文件中各个节区的布局。
  3. 程序头表(Program Header Table):描述文件中各个段的布局。
  4. 节区(Section):包含数据、代码、符号表等信息。
  5. 段(Segment):由操作系统加载的内存区域,通常包含可执行代码、数据等。

二. ELF文件形成与加载

2.1 ELF形成可执行

  • 过程:

将多份源码翻译成为.o文件,再将多个.o文件的section进行合并(也就是链接过程)。
在这里插入图片描述

2.2 ELF控制性文件的加载

大致流程:

  1. 当用户输入命令./a.out运行一个ELF文件时,操作系统执行一系列步骤来加载和执行该文件。
  2. 操作系统的程序加载器(如ld.so或ld-linux.so)负责加载该文件。加载器会读取ELF文件中的头部信息,确定文件类型(例如可执行文件、共享库等)以及如何在内存中组织程序的各个部分。

详细细节如下:

  • ELF文件头(ELF Header)存储描述文件基本信息,如文件类型,目标架构,程序头表的位置和大小等,用于告知操作系统加载器如何处理该文件。
  • 读取程序头表(Program Header Table):它描述了ELF文件中各个段的内存布局,哪些段可执行或可写,主要包括段的类型,段在文件的偏移位置和在内存中的的目标地址及段的大小,段的类型如下:代码段,数据段,BSS段,堆栈等。
  • 加载器的工作:加载器根据程序头表中的信息,将需要加载的段映射到进程的虚拟地址空间中,还未堆栈已初始化或未初始化的静态数据分配内存。同时加载器根据程序头表中的偏移信息将各个段加载到进程的内存中。如代码段樱色到内存的可执行区域,数据段加载到内存的可写区域。
  • 设置程序入口节点:ELF文件包含一个入口点(Entey Point),它是程序开始执行的位置。
  • 执行程序:一旦所有程序的段都被加载到内存,操作系统将程序控制权交给程序的入口点。

2.2.1总结

ELF文件加载的过程可以概括为以下步骤:

  • 加载器读取ELF头,判断文件类型。
  • 读取程序头表,加载需要的段到内存。
  • 内存映射:为代码段、数据段等分配内存。
  • 动态链接(非必须):如果需要,加载和链接共享库。
  • 执行程序:从程序的入口点开始执行

三. ELF加载与进程地址空间

链接过程会对程序中的方法函数进行地址重定位,所以在连接过程之前存在一个不存在的方法也不会报错。
程序有地址,使用统一编址的方式进行编址。
进程mm_struct、vm_area_struct在进程刚刚创建的时候,初始化数据从哪⾥来的?从ELF各个
segment来,每个segment有⾃⼰的起始地址和⾃⼰的⻓度,⽤来初始化内核结构中的[start, end]
等范围数据,另外在⽤详细地址,填充⻚表。

3.1 动态链接与动态库加载

3.1.1 进程如何看到动态库

在编译时,进程将符号引用保留在目标文件中,而不会包含共享库的实际代码。

在链接阶段,进程的符号会与共享库的符号进行连接,生成动态可执行文件。

在程序运行时,操作系统的动态链接器会负责加载共享库,并解析符号,确保程序可以正确调用共享库中的函数。

进程在运行时通过动态链接器映射共享库到内存,进程通过虚拟内存地址访问动态库的函数。

动态链接

_start 函数会调⽤动态链接器的代码来解析和加载程序所依赖的
动态库(shared libraries)。动态链接器会处理所有的符号解析和重定位,确保程序中的函数调
⽤和变量访问能够正确地映射到动态库中的实际地址。

程序如何调用库函数:使用起始虚拟地址+方法偏移量即可定位动态库中的任一方法。

3.2 全局偏移量表GOT(global offset table)

全局偏移量表(Global Offset Table,GOT) 是在 动态链接(Dynamic Linking)过程中用于处理 共享库(Shared Libraries)函数和数据地址的关键数据结构。在程序运行时,GOT 使得程序能够在不依赖编译时已知的物理地址的情况下,动态地访问外部共享库中的函数和数据。

3.2.1 函数调用

当程序执行到需要调用共享库中的函数时,它会通过 GOT 中存储的偏移量访问共享库中的函数地址。在第一次调用时,程序会从 GOT 中跳转到一个间接跳转的地址(通常是一个代理函数),这个代理函数会将实际的符号地址加载到 GOT 中。之后,程序就可以直接使用 GOT 中的地址来调用共享库函数。
PIC:地址无关代码

3.2.2 GOT与动态链接的关系

GOT 是实现 延迟符号解析(Lazy Binding)的关键机制之一。延迟符号解析意味着程序不在启动时就解析所有的符号,而是在需要的时候(例如,第一次调用某个外部函数时)动态地解析并填充符号地址。这使得程序启动更快,且只有在使用外部库时才进行解析。

延迟绑定技术:

由于动态链接在程序加载的时候需要对⼤量函数进⾏重定位,这⼀步显然是⾮常耗时的。为了进⼀
步降低开销,我们的操作系统还做了⼀些其他的优化,⽐如延迟绑定,或者也叫PLT(过程连接表
(Procedure Linkage Table))。与其在程序⼀开始就对所有函数进⾏重定位,不如将这个过程
推迟到函数第⼀次被调⽤的时候,因为绝⼤多数动态库中的函数可能在程序运⾏期间⼀次都不会被
使⽤到。

四. 最后

本文介绍了 ELF 文件 的结构、形成过程、加载机制以及与进程地址空间的关系。ELF文件可以是可执行文件、目标文件、共享库文件或核心转储文件,其主要结构包括 ELF 头、程序头表、节区头表、段和节区等。在 ELF文件的加载过程中,操作系统的加载器负责将文件中的各个段加载到内存,并设置程序的入口点。在进程执行期间,动态链接器负责加载和链接动态库,使用全局偏移量表(GOT) 实现延迟符号解析和函数调用。通过 延迟绑定 和 地址无关代码(PIC) 技术,ELF文件能够高效地管理共享库的函数调用。

路虽远,行则将至;事虽难,做则必成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

经典算法 判断一个图中是否有环

判断一个图中是否有环 问题描述 给一个以0 0结尾的整数对列表,除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图中是否存在环。存在输出YES,不存在输出NO。 输入样例1 6 8 5 3 …

AI与深度伪造技术:如何识别和防范AI生成的假视频和假音频?

引言:深度伪造的崛起 近年来,人工智能技术迅猛发展,其中深度伪造(Deepfake) 技术尤为引人注目。这项技术利用深度学习和神经网络,可以轻松生成高度逼真的假视频和假音频,使人物的面部表情、语音…

ESP32驱动读取ADXL345三轴加速度传感器实时数据

ESP32读取ADXL345三轴加速度传感器实时数据 ADXL345三轴加速度传感器简介ADXL345模块原理图与引脚说明ESP32读取ADXL345程序实验结果 ADXL345三轴加速度传感器简介 ADXL345是一款由Analog Devices公司推出的三轴数字加速度计,分辨率高(13位),测量范围达…

【Linux】系统入门

【Linux】系统初识 起源开源 闭源版本内核内核编号 Linux的安装双系统(不推荐)WindowsLinuxvmware虚拟机vitualbox操作系统的镜像centos 7/ubuntu云服务器租用 Linux的操作lsmkdir 文件名pwdadduser userdel -rrm文件名cat /proc/cpuinfolinux支持编程vim code.c./a.out 运行程…

github配置ssh,全程CV

1)随便找一个文件夹右键进入git bash 2)验证是否已有公私钥文件 cd ~/.ssh ls如果不存在则生成然后获取 生成时一直回车 ssh-keygen -t rsa -C "xxxxxx.com" cd ~/.ssh cat id_rsa.pub如果存在则直接获取 cd ~/.ssh cat id_rsa.pub3)复制 4&#xf…

Dify简介:从架构到部署与应用解析

Dify 是一个开源的生成式 AI 应用开发平台,融合了后端即服务(Backend as a Service, BaaS)和 LLMOps 的理念,旨在帮助开发者快速搭建生产级的生成式 AI 应用。本文将详细解析 Dify 的技术架构、部署流程以及实际应用场景&#xff…

碳化硅(SiC)功率模块方案对工商业储能变流器PCS市场格局的重构

碳化硅(SiC)模块方案(如BMF240R12E2G3)对工商业储能变流器PCS市场格局产生颠覆性的重构: 2025年,SiC模块方案(如BMF240R12E2G3)凭借效率、成本和政策支持的三重优势,将重…

Redis入门(Java中操作Redis)

目录 一 基础概念 1. Redis 核心特点 2. Redis 与 MySQL 的对比 3. Redis的开启与使用 二 Redis的常用数据类型 1 基础概念 2 数据结构的特点 三 Redis基础操作命令 1 字符串操作命令 2 哈希操作命令 3 列表操作命令 4 集合操作命令 5 有序集合操作命令 6 通用命令…

算法思想之位运算(一)

欢迎拜访:雾里看山-CSDN博客 本篇主题:算法思想之位运算(一) 发布时间:2025.4.12 隶属专栏:算法 目录 算法介绍六大基础位运算符常用模板总结 例题位1的个数题目链接题目描述算法思路代码实现 比特位计数题目链接题目描述算法思路…

【基于Servlet技术处理表单】

文章目录 一、实验背景与目的二、实验设计与实现思路1. 功能架构2. 核心代码实现3. 测试用例 总结 一、实验背景与目的 本次实验旨在深入理解Servlet工作原理,掌握JSP与Servlet的协同开发,实现前端表单与后端数据处理的交互。具体目标包括:设…

[OS] mmap | fd是什么 | inode机制 | vfs封装

Linux 下一切皆文件 * 统统抽象为文件,系统封装一层结构体之后,通过指针来访问 * 文章后面的 几个思考题都挺好的 * 后面涉及到的inode 机制,去年暑假的这篇文章,有详细的记录到过 【Linux】(26) 详解磁盘与文件系统:从…

STL详解 - vector的模拟实现

目录 一、整体设计 1.1 核心结构 1.2 迭代器实现 二、核心接口实现 2.1 构造函数系列 🌴默认构造 🌴迭代器范围构造 🌴元素填充构造 2.2 拷贝控制 🌵拷贝构造函数 🌵赋值运算符(现代写法&#xf…

C++第三方库【JSON】nlohman/json

文章目录 优势使用API从文件中读取json从json文本创建json对象直接创建并操作json对象字符串 <> json对象文件流 <> json对象从迭代器读取像使用STL一样的访问STL容器转化为 json数组STL容器 转 json对象自定义类型转化为 json对象 限制 优势 直观的语法&#xff…

超细的ollama下载以及本地部署deepseek项目

Ollama 是一个开源的本地化大语言模型&#xff08;LLM&#xff09;运行和部署工具&#xff0c;专注于让开发者能够快速、高效地在本地运行和管理各种开源大语言模型&#xff08;如 LLaMA、Mistral、GPT 系列等&#xff09;。它提供了一个统一的接口&#xff0c;简化了模型下载、…

【Sequelize】关联模型和孤儿记录

一、关联模型的核心机制 1. 关联类型与组合规则 • 基础四类型&#xff1a; • hasOne&#xff1a;外键存储于目标模型&#xff08;如用户档案表存储用户ID&#xff09; • belongsTo&#xff1a;外键存储于源模型&#xff08;如订单表存储用户ID&#xff09; • hasMany&…

Sentinel实战教程:流量控制与Spring Boot集成

Sentinel实战教程:流量控制与Spring Boot集成 1. Sentinel简介与核心概念 1.1 什么是Sentinel? Sentinel是阿里巴巴开源的流量控制组件,主要用于微服务架构中的流量防护。它通过限流、熔断、热点防护等机制,帮助系统在高并发场景下保持稳定运行。 1.2 核心功能与术语 流…

循环神经网络 - 扩展到图结构之递归神经网络

本文我们来学习递归神经网络(Recursive Neural Network&#xff0c;RecNN)&#xff0c;其是循环神经网络在有向无循环图上的扩展 。 递归神经网络是一类专门设计来处理具有层次结构或树形结构的数据的神经网络模型。它与更常见的循环神经网络&#xff08;Recurrent Neural Net…

Maven超级详细安装部署

1.到底什么是Maven&#xff1f;搞清楚这个 Maven 是一个项目管理工具&#xff0c;主要用于 Java 项目的构建、依赖管理和文档生成。 它基于项目对象模型&#xff08;POM&#xff09;&#xff0c;通过 pom.xml 文件定义项目的配置。 &#xff08;简单说破&#xff1a;就是工程…

电机控制-隆博戈观测器(Luenberger state observer)

本文围绕基于无传感器控制策略的状态观测器展开&#xff0c;介绍其在电机领域的应用、原理、性能表现及无传感器驱动的优劣&#xff1a; 应用场景&#xff1a;适用于燃油泵、风扇等大量固定转速和低成本应用场景。工作原理&#xff1a;状态观测器利用完整的电机微分模型&#…

RK3506+net9+VS2022跨平台调试C#程序

下载GetVsDbg.sh &#xff0c;这脚本会下载一个压缩包&#xff0c;然后解压缩&#xff0c;设置x权限等等。但是目标板子连不上&#xff0c;就想办法获取到下载路径&#xff0c;修改这个脚本&#xff0c;显示这个下载链接后&#xff0c;复制一下&#xff0c;用电脑下下来 修改好…