【iOS】动态链接器dyld

news2024/11/25 15:35:43

参考:认识 dyld :动态链接器

dyld简介

dyld(Dynamic Linker)是 macOS 和 iOS 系统中的动态链接器,它是负责在运行时加载和链接动态共享库(dylib)或可执行文件的组件。在 macOS 系统中,dyld 位于 D/usr/lib/dyld

dyld源码地址

dyld 2

dyld 2(Dynamic Linker 2)是 macOS 和 iOS 系统中的第二代动态链接器。它是前代 dyld 1的进化版本,在性能、功能和安全性方面都有所改进和优化。dyld 2 主要负责在运行时加载和链接动态共享库或可执行文件的组件,并使程序能够正确执行。

以下是 dyld 2 的一些主要特点和改进:

  • 它具有对 C++ 初始化程序语义的正确支持,扩展了 Mach-O 格式,并更新了 dyld ,以便有效支持的 C++ 库。
  • 支持更多的架构及平台。
    自从Power PC上 发布 dyld 2.0 以来,添加了 x86,x86 64 arm,arm64 等架构,支持了 iOS, tvOS, 和 watchOS 平台。
  • 通过多种方式提高了安全性。
    • Codesigning : 代码签名。为了提高应用程序的安全性,dyld 2 支持验证应用程序和共享库的代码签名,以确保它们没有被篡改或恶意修改。
    • ASLR :Address space layout randomization 地址空间配置随机加载。
    • bounds checking:对 Mach-O Header 中的许多内容添加了重要的边界检查功能,从而可以避免恶意二进制数据的注入。
  • 模拟器支持:dyld 2 在 iOS 模拟器中提供了更好的性能和功能支持,使得开发者能够更方便地在模拟器上进行应用程序调试和测试。
  • 提升性能:使用 shared cache 技术完全替代了预绑定 prebinding。
  • 增量加载:dyld 2 支持增量加载(Incremental Loading),即在应用程序启动时,只加载必要的共享库和符号,而不是一次性加载所有动态库。这可以进一步减少启动时间和内存占用。
  • 并发加载:dyld 2 充分利用了多核处理器的优势,支持并发加载动态共享库,从而加速动态链接的过程。
  • 符号隔离:为了提高安全性,dyld 2 引入了符号隔离机制。它将共享库的符号表隔离起来,使得共享库之间的符号不会相互影响,从而避免符号冲突和符号泄

执行流程

在这里插入图片描述

  1. dyld 2 初始化:一旦 dyld 2 加载到内存中,它会执行一些初始化操作,准备好执行动态链接的任务。主要代码在 dyldbootstrap::start,接着执行 dyld::_main dyld::_main 代码较多,是 dyld 加载的核心部分;
  2. 检查并准备环境,比如获取二进制路径,检查环境变量,解析主二进制的 image heade 等信息;
  3. 实例化主二进制的 image loader ,校验主二进制和 dyld 的版本是否匹配;
  4. 检查 shared cache 是否已经 map ,没有的话则先执行 map shared cache 操作;
  5. 检查 DYLD_INSERT_LIBRARIES,有的话则加载插入的动态库(实例化 image loader);
  6. 执行 link 操作。这个过程比较复杂,会先递归加载依赖的所有动态库(会对依赖库进行排序,被依赖的总是在前面),同时在这阶段将执行符号绑定,以及rebasebinding 操作;
  7. 执行初始化方法。Objective-C 的 +load 以及 C 的 constructor方法都会在这个阶段执行;
  8. 读取 Mach-O 的 LC_MAIN段 获取程序的入口地址,调用 main 方法。

加载共享缓存

因为 Foundation 还会依赖一些其他动态库,这些依赖的其他库还会再依赖更多的库,所以相互依赖的符号会很多,需要处理的时间也会比较长。这里系统上的动态链接器会使用共享缓存,共享缓存在 /var/db/dyld/。当加载 Mach-O 文件时,动态链接器会先检查是否有共享缓存。每个进程都会在自己的地址空间映射这些共享缓存,这样做可以起到优化 App 启动速度的作用。

加载共享缓存(Shared Cache)是 dyld 2 在 macOS 和 iOS 系统中用于加快动态链接的一项优化技术。共享缓存是一种预先生成的动态库集合,包含了多个应用程序常用的动态共享库。当应用程序启动时,dyld 2 可以直接从共享缓存中加载所需的动态库,而无需再重新从磁盘上逐个加载动态库,从而加快应用程序的启动速度。

共享缓存的加载过程可以简要概括如下:

  1. 生成共享缓存:在系统安装或更新时,操作系统会预先生成一个共享缓存,其中包含了多个常用的系统动态共享库和框架。这个过程通常在设备首次启动、操作系统升级或开发者重新编译系统库时进行。
  2. 共享缓存路径:共享缓存被保存在系统文件中,其路径是 /System/Library/Caches/com.apple.dyld/dyld_shared_cache_x86_64(macOS)/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64(iOS)等,具体路径会根据设备和架构而有所不同。
  3. 应用程序启动:当应用程序启动时,dyld 2 会首先检查共享缓存是否可用,并尝试加载共享缓存。
  4. 加载共享缓存:如果共享缓存可用,dyld 2 会直接将共享缓存映射到内存中,并建立共享缓存中动态库与应用程序之间的链接关系。
  5. 符号解析和重定位:在加载共享缓存后,dyld 2 会进行符号解析和重定位,将应用程序中的符号引用与共享缓存中的符号地址进行关联。
  6. 动态库链接:如果应用程序还依赖其他未包含在共享缓存中的动态共享库,dyld 2 会根据需要逐个加载这些动态共享库,并进行链接和符号解析。
  7. 应用程序初始化:一旦所有动态共享库都加载并完成符号解析后,dyld 2 会开始执行应用程序的main()函数,从而正式启动应用程序的执行。

动态库加载

链接的共用库分为静态库和动态库:

  • 静态库是编译时链接的库,需要链接进 Mach-O 文件里,如果需要更新就要重新编译一次,无法动态加载和更新;
  • 动态库是运行时链接的库,使用 dyld 就可以实现动态加载。

Mach-O 文件是编译后的产物,而动态库在运行时才会被链接,并没参与 Mach-O 文件的编译和链接,所以 Mach-O 文件中并没有包含动态库里的符号定义。也就是说,这些符号会显示为“未定义”,但它们的名字和对应的库的路径会被记录下来。运行时通过 dlopen 和 dlsym 导入动态库时,先根据记录的库路径找到对应的库,再通过记录的名字符号找到绑定的地址。

dlopen 会把共享库载入运行进程的地址空间,载入的共享库也会有未定义的符号,这样会触发更多的共享库被载入。dlopen 也可以选择是立刻解析所有引用还是滞后去做。dlopen 打开动态库后返回的是引用的指针,dlsym 的作用就是通过 dlopen 返回的动态库指针和函数符号,得到函数的地址然后使用。

dyld 2 存在的问题

  • Parse mach-o headers 可以使用撰改过的 Mach-O 文件头进行攻击,
  • Find dependencies 可以使用 @rpaths 即搜索路径。通过撰改这些路径或者将库插到适当的位置,可以破坏程序;
  • Perform symbol lookups 符号查找部分,因为在给定的库中,除非进行软件更新或者在磁盘上更改库,符号将始终位于库中的相同偏移位置;

dyld 3

dyld 3是全新的动态链接器,它完全改变了动态链接概念。WWDC-App Startup Time: Past, Present, and Future 提到在iOS 13系统中,iOS 全面采用新的 dyld 3 以替代之前版本的 dyld 2。dyld 3带来了可观的性能提升,减少了APP的启动时间。 因为 dyld 3 完全兼容 dyld 2,API 接口是一样的,所以在大部分情况下,开发者不需要做额外的适配就能平滑过渡。

执行流程

在这里插入图片描述

dyld 3 包含这三个部分:

  1. 进程外 Mach-O 分析器和编译器 (out-of-process mach-o parser)由于 dyld 2 存在的问题,dyld 3 中将采用提前写入把结果数据缓存成文件的方式构成一个 lauch closure(可以理解为缓存文件)
  2. 进程内引擎 执行 launch closure 处理 (in-process engine)验证”lauch closures“是否正确,映射dylib,执行main函数。此时,它不再需要分析mach-o header和执行符号查找,节省了不少时间。
  3. launch closure 缓存服务 (launch closure cache )系统程序的 lauch closure 直接内置在 shared cache 中,而对于第三方APP,将在APP安装或更新时生成,这样就能保证 launch closure 总是在 APP 打开之前准备好。

大多数程序启动会使用缓存,而不需要调用进程外 mach-o分析器或编译器;并且 launch closure 比 Mach-O 更简单,它们是内存映射文件,不需要用复杂的方法进行分析,我们可以简单地验证它们,其作用是为了提高速度

dyld 3的符号缺失问题

dyld 2 默认采取的是 lazy symbol 的符号加载方式,但在 dyld 3中,在 App 启动之前,符号解析的结果已经在 lauch closure 内了,所以 lazy symbol 就不再需要。这时,如果有符号缺失的情况,APP 的行为会有不同:在 dyld 2 中,首次调用缺失符号时 APP 会 crash;而 dyld 3 中,缺失符号会导致 APP 一启动就会 crash。

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

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

相关文章

Docker 安装 和 GPU 支持

一、Docker安装过程(ubuntu18.04环境) 清华镜像 docker 安装:docker-ce | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 1、由于apt官方库里的docker版本可能比较旧,所以先卸载可能存在的旧版本&…

Java 设计模式——原型模式

目录 1.概述2.结构3.实现3.1.浅拷贝3.2.深拷贝3.2.1.通过对象序列化实现深拷贝(推荐)3.2.2.重写 clone() 方法来实现深拷贝 4.优缺点5.使用场景 1.概述 (1)原型模式 (Prototype Pattern) 是一种创建型设计模式,是通过…

【2023裸辞失业后之初学RocketMQ】

目录 RocketMQ概述MQ概述常见的MQ产品常见的协议 Rocket的安装和启动基本概念系统架构安装RocketMQ和控制台 RocketMQ概述 MQ概述 Message Queue:是提供消息队列服务的中间件,提供消息生产,存储,消费的全过程。 作用&#xff1a…

刘铁猛C#语言教程——表达式详解1

表达式的定义 对以上文档的翻译: 对以上文档的代码解释:表达式是为了实现具体的算法逻辑并得到一个具体的值,而表达式的返回值可以是一个单值,也可以是实例,方法,或者命名空间;例如:…

微服务入门---SpringCloud(一)

微服务入门---SpringCloud(一) 1.认识微服务1.0.学习目标1.1.单体架构1.2.分布式架构1.3.微服务1.4.SpringCloud1.5.总结 2.服务拆分和远程调用2.1.服务拆分原则2.2.服务拆分示例2.2.1.导入Sql语句2.2.2.导入demo工程 2.3.实现远程调用案例2.3.1.案例需求…

当今网络的基本情况

1 网络表示方法和网络拓扑 1.1 网络表示方法 网络架构师和管理员必须能够展示他们的网络将是什么样子。他们需要能够轻松地看到哪些组件连接到其他组件,它们将位于何处,以及它们将如何连接。网络图通常使用图标(如图中所示)来表…

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…

数据结构与算法-排序算法

数据结构与算法之排序算法 1 使用递归的方式求最大值2 时间复杂度3 选择排序和冒泡排序的时间复杂度分析4 插入排序时间复杂度分析 (O(N^2))5 二分法的详解与扩展6 对数器7 归并排序8 归并排序的应用9 逆序对问题10 归并排序非递归方式11 快速排序12 堆排序13 桶排序 1 使用递归…

并行计算-OPENMP(windows)

并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求解同一问题,即将被求解的问题分解成若干个部分,各…

深度学习(一)

目录 一、特征工程的作用 二、深度学习的应用 三、得分函数 四、损失函数 五、前向传播 六、反向传播 一、特征工程的作用 数据特征决定了模型的上限预处理和特征提取是最核心的算法与参数选择决定了如何逼近这个上限 二、深度学习的应用 无人驾驶人脸识别分辨率重构 深…

国产龙芯2k1000开发板运行SylixOS嵌入式实时系统--迅为电子

龙芯生态体系越来越完善,继RK3568开发板成功搭载SylixOS国产实时操作系统后,迅为的国产龙芯2K1000开发平台也可以流畅运行SylixOS国产实时操作系统了。 SylixOS 采用抢占式、多任务、硬实时的方式来设计整个操作系统。已广泛适用于电力、工业自动化、轨道…

为什么要配置环境变量(深析)

为什么要配置环境变量(深析) 前言:大家学习java首先听到的就是jdk,配置环境变量,当时我听到这个也一脸雾水,这是个什么东西,当时就稀里糊涂跟着老师一步步下载安装,弄好了也不知道是…

安全基础 --- html基础标签 + DNS工作原理

html基础标签 &#xff08;1&#xff09;id id属性是元素在网页内的唯一标识符。 比如&#xff0c;网页可能包含多个<p>标签&#xff0c;id属性可以指定每个<p>标签的唯一标识符。 <p id"p1"></p> <p id"p2"></p>…

UE4/5C++多线程插件制作(十四、MTPAbandonable)

MTPAbandonable 在头文件中创建新的文件夹,MTPAbandonable,里面是MTPAbandonable.h,cpp也一样如此: h实现 构造函数接受一个FSimpleDelegate类型的参数InThreadDelegate,用于指定任务在后台线程中执行时要执行的操作。 DoWork()函数定义了任务的具体执行逻辑,需要根据…

NLog同时输出到文件、控制台、RichTextBox

效果 项目 VS2010.net4.0NLogNLog.Windows.Forms 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using NLog;namespac…

【Docker 网络】

文章目录 一、Docker 网络1、Docker 网络实现原理2、查看容器的输出和日志信息3、Docker 的网络模式4、网络模式详解1&#xff0e;host模式2&#xff0e;container模式3&#xff0e;none模式4&#xff0e;bridge模式5&#xff0e;自定义网络1、创建自定义网络 二、资源控制1&am…

初识TDMQ

目录 一&#xff1a;需求背景二&#xff1a;相关文档三&#xff1a;验证TDMQ广播消息 一&#xff1a;需求背景 目前公司需要将决策引擎处理的结果&#xff0c; 一部分数据交给下游分析/入黑/通知等功能。因此就需要决策引擎生产结果让多方下游去消费。 而我需要实现下游的一部…

数据类型的分类

数据类型的分类 java中的 变量 按照数据类型来分类&#xff1a; 基本数据类型&#xff08;8种&#xff09;&#xff08;primitive type&#xff09;&#xff1a; 整型&#xff1a;byte、short、int、long、浮点型&#xff1a;float、double字符型&#xff1a;char布尔型&#x…

/var/empty/sshd must be owned by root and not group or world-writable

/var/empty/sshd must be owned by root and not group or world-writable 这个是权限的问题 可采取以下两步解决 chown -R root.root /var/empty/sshd chmod 744 /var/empty/sshd service sshd restart

80v转5v芯片-电动车/汽车降压芯片方案

Q: 什么是80v转5v芯片&#xff1f;什么它在电动车和汽车中有应用需求&#xff1f; A: 80v转5v芯片是一种电源转换芯片&#xff0c;可以将输入电压范围为9v至100v的直流电源转换为输出电压为5v&#xff0c;并且可以进行可调。这种芯片在电动车和汽车领域有广泛的应用需求。电动…