【iOS】动态链接器dyld

参考:认识 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.mzph.cn/news/6814.shtml

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

相关文章

STM32MP157驱动开发——按键驱动(定时器)

“定时器 ”机制: 内核函数 定时器涉及函数参考内核源码:include\linux\timer.h 给定时器的各个参数赋值: setup_timer(struct timer_list * timer, void (*function)(unsigned long),unsigned long data):设置定时器&#xf…

解决 npm ERR! missing script: build 错误的方法

系列文章目录 文章目录 系列文章目录前言一、错误原因二、解决方法:三、注意事项:总结 前言 在使用 npm 进行前端项目构建时,有时会遇到错误信息 “npm ERR! missing script: build”,该错误通常发生在没有定义构建脚本时。本文将…

多元函数的概念

目录 多元函数的极限: 例题1: 例题2: 多元函数的连续性 连续函数的性质 偏导数 高阶偏导数 定理1: 全微分 可微的必要条件 用定义来判断是否可微 可微的充分条件 连续偏导可微的关系 多元函数的极限: 对于一个二元…

macOS Ventura 13.5 (22G74) 正式版发布,ISO、IPSW、PKG 下载

macOS Ventura 13.5 (22G74) 正式版发布,ISO、IPSW、PKG 下载 本站下载的 macOS Ventura 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也…

服务器数据库中了Locked勒索病毒,企业应该如何正确处理并采取后续防护措施

网络技术的发展极大地方便了人们的工作生活,但同样带来了一定的网络安全威胁,其中较为危险的威胁就是勒索病毒攻击,勒索病毒不仅会给我们的计算机系统带来破坏,还会加密我们的重要文件数据来敲诈勒索,只有用户支付的赎…

深度学习超参数

每个超参数在训练中的作用: policy: 决定智能体学习环境时使用的策略网络结构,如多层感知机策略(MlpPolicy)或卷积神经网络策略(CnnPolicy)。 learning_rate: 控制神经网络权重更新的速度,影响…

提高可视性的五大方法可增强 Horizon Cloud 下一代平台的性能和用户体验

我们在 VMware Explore US 2022 推出了 VMware Horizon Cloud 下一代平台。该平台为使用现代化虚拟桌面和应用的客户提供了一个新的混合型桌面服务(DaaS)架构,其围绕降低成本和提高可扩展性而构建。首次发布后,我们在 VMware Expl…

gerrit 从安装到出坑

一般公司在做代码审核的时候选择codereview gerrit来处理代码的入库的问题。 它是通过提交的时候产生Change-Id: If4e0107f3bd7c5df9e2dc72ee4beb187b07151b9 来决定是不是入库,一般如果不是通过这个管理,那么就是我们通常的操作 git add . git comm…

设计模式-工厂模式

定义 工厂模式是用来创建对象的一种最常用的设计模式,不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂 其就像工厂一样重复的产生类似的产品,工厂模式只需要我们传入正确的参数&#…

rust 配置

rustup 镜像 在 cmd 中输入以下代码,设置环境变量 setx RUSTUP_UPDATE_ROOT https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup setx RUSTUP_DIST_SERVER https://mirrors.tuna.tsinghua.edu.cn/rustupcrates.io 索引镜像 在 C:\Users\用户名\.cargo\config 文…

【MySQL】MySQL HeatWave 介绍

HeatWave是一个分布式、可扩展、无共享、内存中、混合柱状的查询处理引擎,专为获得极致性能而设计。可以通过向MySQL数据库系统添加一个HeatWave集群来启用它。 HeatWave 是一种大规模并行、高性能内存查询加速器,可将分析工作负载、混合工作负载和机器…

Linux 学习记录55(ARM篇)

Linux 学习记录55(ARM篇) 本文目录 Linux 学习记录55(ARM篇)一、使用C语言封装GPIO函数1. 封装GPIO组寄存器2. 封装GPIO模式以及相关配置3. 封装GPIO初始化结构体4. 使用自己的封装配置GPIO 一、使用C语言封装GPIO函数 1. 封装GPIO组寄存器 #define GPIOA ((GP…

刷题日记09《图论基础》

图的存储结构 对于图结构而言,常见的存储结构主要有两种:邻接表和邻接矩阵: 邻接表很直观,我把每个节点 x 的邻居都存到一个列表里,然后把 x 和这个列表关联起来,这样就可以通过一个节点 x 找到它的所有相邻…

rust持续学习Box::leak

Box就是unique_ptr 这个函数的功能是消费box返回一个全局变量&#xff01; 写一个函数&#xff0c;想要真的返回全局变量&#xff0c;感觉用这个是个好的做法 fn Foo()->Option<&static mut A> {let a Box::new(A());Some(Box::leak(a)) }这样就能当真拿到这个全…

【算法与数据结构】222、LeetCode完全二叉树的节点个数

文章目录 一、题目二、一般遍历解法三、利用完全二叉树性质四、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、一般遍历解法 思路分析&#xff1a;利用层序遍历&#xff0c;然后用num记录节点数量。其他的例如…

家庭网络设计方案

网络设计方案1 设备清单&#xff1a; 设备类型数量安装位置设备作用设备连接关系AC1二楼客厅提供无线网络覆盖和管理连接到路由器AP5一楼三个房间、三楼小厅、四楼大房间扩展无线网络覆盖&#xff0c;通过POE方式供电连接到AC或交换机交换机1一楼车库连接所有有线网络接口&am…

视频增强技术-去噪

本文介绍了关于视频增强技术的相关方法包括传统方法和基于深度学习的方法&#xff0c;并给出了他们的对比实验结果&#xff0c;最后对它们简单的做了总结&#xff0c;文中有一些图片和总结来自于网上其他博主的文章&#xff0c;已在文中标记并给出了相关的原文链接&#xff0c;…

一文掌握如何前后端分离?

随着科技的进步和发展&#xff0c;低代码开发产品拥有广阔的市场前景。前后端分离似乎早已经是发展趋势了&#xff0c;因为做好前后端分离对于前后端的工程师而言是非常有利的&#xff0c;这样也有利于提升办公协作效率。那么&#xff0c;如何前后端分离&#xff1f;分别都有哪…

【期刊征稿】2区遥感类SCI,自引率低,检索稳定,3个月左右录用~

一、期刊简介 2区遥感类SCI 【期刊概况】3.0-4.0↑, JCR2区&#xff0c;中科院4区&#xff1b; 【终审周期】走期刊部系统&#xff0c;3个月左右录用&#xff1b; 【检索情况】SCI在检&#xff0c;正刊&#xff1b; 【版面情况】5-10篇版面&#xff1b; 二、征稿范围 基…

【机器学习】支持向量机SVM入门

优化目标 相较于之前学习的线性回归和神经网络&#xff0c;支持向量机&#xff08;Supprot Vector Machine&#xff0c;简称SVM&#xff09;在拟合复杂的非线性方程的时候拥有更出色的能力&#xff0c;该算法也是十分经典的算法之一。接下来我们需要学习这种算法 首先我们回顾…