musl libc ldso 动态加载研究笔记:02

前言

  • 本篇继续研究 musl libc ldso 的动态加载过程中遇到的关键性的概念:到底要加载ELF 文件的哪些内容到 内存

  • 当前如果遇到 ELF 动态加载,当前系统需要有【文件系统】,并且有较大的内存,因为 ELF 文件是无法直接运行的,首先通过解析 ELF 头部 获取入口函数,把需要载入到内存中的文件内容复制到指定内存区域,然后执行ELF 的入口函数,通常不是 ELF的 main 函数,而是更早的执行函数,如 _start 或者 _dlstart 函数。此时 PC 指针指向 ELF 加载的基地址 + ELF 入口函数。

ELF 加载基地址

  • 一个 ELF 文件,是否可以随意的加载?

当前验证发现: ELF 文件包括我们通常见到的 可以执行的文件,以及 共享库(如 xx.so)。共享库没有连接地址,基址是 0,但入口函数不一定是 0,如果遇到入口函数也是 0 的,需要注意这个 偏移地址 为 0 的入口函数,是否只是个空的符号,无法执行

  • 为何有的 xxx.so 也称作 ELF 文件? 比如 musl libc.so,本身是个 库,但是它 有入口函数,并且可以执行。 当前 musl libc.so 确实如此,通常我们一般区分 执行文件与 库,库不用于执行。但是 musl libc.so 具备执行的功能,就像是我们见到的普通的执行文件,但是它依旧具备普通库的功能,为其他动态编译的应用程序提供共享库。

  • 作为 共享库与可执行 集成在一起的 musl libc.so,基地址:0,入口函数不为0,基地址为0 可以重定位加载,如手动把 libc.so 加载到 0x200000 地址, 那么 libc.so 的入口函数就是: 0x200000 + libc.so 入口地址

  • 普通静态或者动态链接的ELF 文件,由于基地址 不为0,就无法手动加载到 随意的地址。

  • 如下 ELF 文件:基地址 0x200000,这个基地址跟链接脚本中的链接地址有关系,可以查看这个 elf 的连接脚本配置

  • 入口点:入口地址,这个地址 已经是基于基地址 0x200000的,所以这个地址就不能随机加载了。如果想改变 这个 elf 的基地址,需要更改 相应的 链接脚本 链接地址的设置

在这里插入图片描述

动态加载需要加载哪些 ELF 内容到内存

  • 有的 ELF 文件特别的大,尤其是开启了 【DEBUG】的,比如编译时使用 -O0 -g, gdb 的调试信息都加入 ELF 文件了, ELF 文件不同于单片机的烧写文件 bin 文件,里面还有一些内容,如调试信息,是不需要加载到内存的,那么到底需要加载什么内容呢?

  • 这部分可以查看 Linux 内核代码 elf 加载部分,如 linux-6.3.8/fs/binfmt_elf.c 中的 load_elf_binary

  • Linux 系统由于默认支持 mmu,执行文件的 mmap 映射,所以没有文件没有使用常规的 内存分配,不过依旧是先把文件内容映射 到用户地址空间,之所以不填充,是因为 Linux文件mmap 有缺页异常机制,需要访问时才会真正载入文件内容到内存,这样有很多好处,开始只映射(占位子)不加载,这样节省了加载时间,一个 ELF 文件,不可能上来全部执行到,可能只会执行部分内容,这样采用 访问时再加载,将会节省数量可观的内存,节省大量的加载时间。加上文件 mmap 有 cache 功能,如果加载过后,缓存暂时不清掉,这样下次执行就不再重复加载了。Linux 这个文件mmap 映射加载机制,对于 ELF 加载非常的有用。

  • 经过熟悉 Linux 的 load_elf_binary ,发现只需要 加载 PT_LOAD

  • 那么 ELF 的 PT_LOAD 段,真的覆盖 ELF 的所有需要加载到内存中的内容范围吗?有没有漏下的?或者说 elf 不是还有 重定位、符号、.text.data、等等吗?这些包含在里面吗?

  • 通过 elf 查看工具,加上对实际加载到内存的内容进行反向 dump 出来,肯定的一点就是: ELF 的 PT_LOAD 段 包含了所有需要加载到内存的文件内容,是所有,如果在其他的系统上,发现动态加载后, 内存中的文件内容不正确,或者部分内容为0,需要查看文件加载部分是否有处理不当的地方。

查看 PT_LOAD

  • 可以使用 Die 这个工具,查看 ELF文件

在这里插入图片描述

  • 这里了解到, PT_LOAD 段 第一个段 文件偏移是 0,也就是把 ELF 文件头部也加入了内存

  • 两个 PT_LOAD 段 的大小:Program 中的 p_filesz 就是当前的段大小,总大小: 0x23528 + 0x9f8 = 0x23f20,之所以这么计算,是因为 当前的两个段 是连在一起的。

  • 由于段有多个节(section),可以查看 节 信息,

在这里插入图片描述

  • 通过 计算 PT_LOAD 段的总大小,知道 这个 elf 文件 前面 0 ~ (0x23f20 -1) ,也就是 0x23f20 个字节已经加载到内存,剩下 的节,.bss 没有实际内容,但内存中需要留位置,并且清 0。其他的节全部是 调试信息 debug 相关的。

  • 所以通过加载 PT_LOAD 段,确实实现了整个 ELF 必需文件内容的全部加载

加载大小

  • 这里需要提一下:段的加载大小,不是 段的 p_filesz,而是 段的 p_memsz, p_memsz 一般等于或者大于 p_filesz,超出的大小,就是 .bss section 的大小,这部分大小需要手动清零,不清零,可能引发程序启动后的异常,比如定义了一个变量,但是没有初始化就使用,而程序员默认没有初始化的变量会被初始化 为 0。 清零 .bss 就是清零 PT_LOAD 段 中 p_memsz - p_filesz 大小的区域,这个区域的起始地址应该是: base +elf_ppnt->p_vaddr + elf_ppnt->p_filesz,如果是静态连接编译的 elf 程序, base 是0,也就是 elf_ppnt->p_vaddr + elf_ppnt->p_fileszelf_ppnt->p_vaddr 是这个文件段的起始地址。

  • 这里需要提一下: 段的 p_offset,这个是相对文件本身的偏移,通过情况下, p_offsetp_vaddr 是相同的,但也有不相同的。所以在文件填充时,需要把 文件内容 偏移 p_offset 后,读取到内存地址 p_vaddr 的位置,也就是说: 文件内容的存放位置 与 文件映射到内存的地址,并非一一对应。

在这里插入图片描述

小结

  • 本篇注意讲解一下 ELF文件在 动态加载时需要加载哪些内容到内存,注意这里的动态加载,是动态加载 ELF 文件,这个 ELF文件,不单是 动态编译链接的 ELF,也包括静态编译链接的 ELF 以及 经常遇到的 动态共享库 (xx.so)

  • 需要熟悉 ELF 的 头部、Program Header、了解 各个 Segment 段,了解 Section 节信息,这样对理解 动态加载程序,熟悉 动态加载非常有用。

  • 需要了解操作系统的进程、线程机制,文件映射 mmap 机制。注意需要反复确认 内存的文件内容是否正确、完整。可以同 dump 的方式,把内存中的文件内容 dump 成一个文件,然后与实际的文件进行内容对比。

  • 需要深刻了解 文件段的本身的偏移 :p_offset 与 内存地址 p_vaddr 的关系,也需要了解 段真实文件大小 p_filesz 与 p_memsz 的关系,也就是 .bss 节的存在

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【解析postman工具的使用---基础篇】

postman前端请求详解 主界面1.常见类型的接口请求1.1 查询参数的接口请求1.1.1 什么是查询参数?1.1.2 postman如何请求 1.2 ❤表单类型的接口请求1.2.1 复习下http请求1.2.2❤ 什么是表单 1.3 上传文件的表单请求1.4❤ json类型的接口请求 2. 响应接口数据分析2.1 postman的响…

Qt应用开发(基础篇)——MDI窗口 QMdiArea QMdiSubWindow

一、前言 QMdiArea类继承于QAbstractScrollArea,QAbstractScrollArea继承于QFrame,是Qt用来显示MDI窗口的部件。 滚屏区域基类 QAbstractScrollAreahttps://blog.csdn.net/u014491932/article/details/132245486 框架类 QFramehttps://blog.csdn.net/u01…

【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPushConsumer的实现原理及源码分析

RocketMQ开源是使用文件作为持久化工具,阿里内部未开源的性能会更高,使用oceanBase作为持久化工具。 在RocketMQ1.x和2.x使用zookeeper管理集群,3.x开始使用nameserver代替zk,更轻量级,此外RocketMQ的客户端拥有两种的…

公网远程连接Redis数据库「内网穿透」

文章目录 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址连接 前言 洁洁的个人主页 我就问你有没有发挥&#xff0…

GuLi商城-前端基础Vue-生命周期和钩子函数

下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它 的参考价值会越来越高。 VUE 的生命周期指的是组件在创建、运行和销毁过程中所经历的一系列事件,通过这些事件可以 让开发者在不同阶段进行相应的…

【C语言】指针的进阶

目录 一、字符指针 二、指针数组 三、数组指针 1.数组指针的定义 2.&数组名和数组名区别 3.数组指针的使用 四、数组参数与指针参数 1.一维数组传参 2.二维数组传参 3.一级指针传参 4.二级指针传参 五、函数指针 六、函数指针数组 七、指向函数指针数组的指针…

【使用教程】在Ubuntu下运行CANopen通信PMM伺服电机使用教程(NimServoSDK_V2.0.0)

本教程将指导您在Ubuntu操作系统下使用NimServoSDK_V2.0.0来运行CANopen通信的PMM系列一体化伺服电机。我们将介绍必要的步骤和命令,以确保您能够成功地配置和控制PMM系列一体化伺服电机。 NimServoSDK_V2.0.0是一款用于PMM一体化伺服电机的软件开发工具包。它提供了…

金融语言模型:FinGPT

项目简介 FinGPT是一个开源的金融语言模型(LLMs),由FinNLP项目提供。这个项目让对金融领域的自然语言处理(NLP)感兴趣的人们有了一个可以自由尝试的平台,并提供了一个与专有模型相比更容易获取的金融数据。…

Git 设置代理

Git 传输分两种协议,SSH和 http(s),设置代理也需要分两种。 http(s) 代理 Command Line 使用 命令行 模式,可以在Powershell中使用以下命令设置代理: $env:http_proxy"http://127.0.0.1:7890" $env:https_proxy&quo…

算法通关村第十关 | 归并排序

1. 归并排序原理 归并排序(MERARE-SORT)简单来说就是将大的序列先视为若干个比较小的数组,分成比较小的结构,然后是利用归并的思想实现的排序方法,该算法采用经典的分治策略(分就是将问题分成一些小的问题分…

数学建模之“聚类分析”原理详解

一、聚类分析的概念 1、聚类分析(又称群分析)是研究样品(或指标)分类问题的一种多元统计法。 2、主要方法:系统聚类法、有序样品聚类法、动态聚类法、模糊聚类法、图论聚类法、聚类预报法等。这里主要介绍系统聚类法…

【uniapp】picker mode=“region“ 最简单的省市区 三级联动

省市区 picker template <picker mode"region" :value"date" class"u-w-440" change"bindTimeChange"><u--inputborder"bottom"class"u-fb u-f-s-28"placeholder"请选择省市区"type"te…

vue实例挂载过程

以下仅为个人见解。 1.大致流程&#xff1a; new Vue()时会调用initMixin(Vue)将_init挂载到vue原型上&#xff1b;在_init()中调用$mount()方法($mount()方法也是挂载到vue原型上的)编译template模版&#xff0c;并生成render()函数&#xff1b;挂载到vm上后&#xff0c;会…

前端node.js入门-前端工程化与模块化

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Node.js 入门 什么是 Node.js&#xff1f; 什么是前端工程化&#xff1f; Node.js 为何能执行 JS&…

神经网络基础-神经网络补充概念-08-逻辑回归中的梯度下降算法

概念 逻辑回归是一种用于分类问题的机器学习算法&#xff0c;而梯度下降是优化算法&#xff0c;用于更新模型参数以最小化损失函数。在逻辑回归中&#xff0c;我们使用梯度下降算法来找到最优的模型参数&#xff0c;使得逻辑回归模型能够更好地拟合训练数据。 逻辑回归中的梯…

C语言——通讯录详解(动态版)

通讯录详解 前言&#xff1a;一、定义一个通讯录二、初始化三、增加联系人3.1 给通讯录扩容3.2增加联系人 四、释放内存五、完整代码 前言&#xff1a; 我们已经学过了通讯录的静态版&#xff0c;但是它的缺点很明显&#xff0c;通讯录满了就添加不了联系人了啦。我再让通讯录升…

山东布谷科技直播软件源码Nginx服务器横向扩展:搭建更稳定的平台服务

在直播软件源码平台中&#xff0c;服务器扮演着重要的角色&#xff0c;关系着视频传输、数据处理、用户管理等工作的顺利完成。随着互联网的迅猛发展&#xff0c;直播行业也随之崛起&#xff0c;全世界的人们都加入到了直播软件源码平台中&#xff0c;用户流量的增加让服务器的…

Mac鼠标增强工具Smooze Pro

Smooze Pro是一款Mac上的鼠标手势增强工具&#xff0c;可以让用户使用鼠标手势来控制应用程序和系统功能。 它支持多种手势操作&#xff0c;包括单指、双指、三指和四指手势&#xff0c;并且可以自定义每种手势的功能。例如&#xff0c;您可以使用单指向下滑动手势来启动Expos视…

web JS高德地图标点、点聚合、自定义图标、自定义窗体信息、换肤等功能实现和高复用性组件封装教程

文章目录 前言一、点聚合是什么&#xff1f;二、开发前准备三、API示例1.引入高德地图2.创建地图实例3.添加标点4.删除标点5.删除所有标点&#xff08;覆盖物&#xff09;6.聚合点7.自定义聚合点样式8.清除聚合9.打开窗体信息 四、实战开发需求要求效果图如下&#xff1a;封装思…

pdf怎么合并在一起?这几个合并方法了解一下

pdf怎么合并在一起&#xff1f;在日常工作、学习和生活中&#xff0c;我们常常会遇到需要将多个PDF文件合并成一个文件的情况。比如&#xff0c;在学术论文写作中&#xff0c;我们可能需要将多篇论文合并成一个文件进行打印和提交。在工作中&#xff0c;我们可能需要将多个报告…