dyld 加载 Mach-O
前言
最近看 ObjC的runtime 是怎么实现 +load 钩子函数的实现。进而引申分析了 dyld 处理 Mach-O 的这部分机制。
1.简单分析 Mach-O 在dyld 中是如何被加载到内存中的;
2.分析了 +load 的 特殊加载时机;
+ load
上图的调用栈告诉我们哪些函数被调用了。
dyld 是Apple 的动态链接器;在 xnu 内核为程序启动做好准备后,就会将 PC 控制权交给 dyld 负责剩下的工作 (dyld 是运行在 用户态的, 这里由 内核态 切到了用户态)。
每当有新的镜像加载之后,都会执行 load-images 方法进行回调,这里的回调是在整个ObjC runtime 初始化时 -objc-init 注册的 :
有新的镜像被 map 到 runtime 时,调用 load-images 方法,并传入最新镜像的信息列表 infoList:
这里的镜像就是 一些 System framework 的二进制。
进入 下图函数 load-images-nolock 查找 load 函数
调用 prepare-load-methods 对 load 方法的调用进行准备(将需要调用 load 方法的类添加到一个列表中)
调用 -getObjc2NonlazyClassList 获取所有的类的列表之后,会通过 remapClass 获取类对应的指针,然后调用 schedule-class-load 递归地 将当前类和没有调用 + load 父类进入列表。
在执行 add-class-to-loadable-list(cls) 将当前类加入加载列表之前,会先把父类加入待加载的列表,保证父类在子类前调用 load 方法。
在将镜像加载到运行时、对 load 方法的准备就绪,执行 call-load-methods,开始调用 load 方法:
其中 call-class-loads 会从一个待加载的类列表 loadable-classes 中寻找对应的类,然后找到 @selector(load) 的实现并执行。
分析到这里,已经能得知 load 函数是如何被调用的。
接下来分析 dyld 这部分怎么加载镜像的
1.1 数据结构
mach-o 文件头 操作。
1.2 ImageLoader
每一个加载的 Mach-O 文件都会存在这样一个ImageLoader 的 实例,上图可以看出 这里ImageLoader是一个抽象类,每一种具体的Mach-O 文件都会继承 ImageLoader类, 继承关系 如下图:
在加载时会根据Mach-O的格式不同选择生成不用的实例。
1.3 -main
在调用-main 函数之后,做了一下几件事情:
选择运行环境(iOS 模拟器)
初始化数据、设置全局变量、上下文信息
检查文件是否Restricted
走完这些流程,就会调用 instantiateFromLoadedImage 函数,开始加载Mach-O 并且实例化 为 ImageLoader。
1.4 instantiateFromLoadedImage
这个函数做了三件事情:
检查Mach-O 文件是否合法
初始化 ImageLoader 实例
调用addImage 函数添加 初始化后的实例到管理模块中
1.5 isCompatibleMachO
Mach-O 文件的合法性检查:
mach-header 中的 cputype与当前运行的CPU 版本是否支持
mach-header 中的 subtype 在该CPU 架构下的所有版本都可以支持
cputype 就是CPU 平台, x86,ARM ,POWERPC 等, 而subtype 就是同一个平台下的不同版本, 例如:arm7,arm7.
1.6 ImageLoaderMachO: : instantiateMainExecutable
该函数主要通过 sniffLoadCommands 函数来判断 Mach-O 文件是否是压缩过的,然后分别 选择不同的 子类实例化。
1.7 sniffLoadCommands
这个函数主要做两件事情
判断Mach-O文件是classic的还是compressed的。
获取mach-O文件的segment的数量。
1.8 ImageLoaderMachOClassic: :instantiateMainExecutable
classic 与 compressed 的初始化大同小异,先分析Classic 的实现
可以看到加载的核心代码 还在 instantiateStart 函数中
1.9 instantiateStart
这里仍然没有出现加载的核心代码,只是根据之前获得的数据申请分配了内存,并计算 segments的 指针。 ImageLoaderMachOClassic 的构造函数才是加载 的核心逻辑。
2.0 ImageLoaderMachOClassic
根据Mach-O 文件 segments 将数据加载到 内存中, 任何返回 调用 addImage 函数。
2.1 addImage
这个函数只是做了数据更新
将image 添加到管理容器中
更新了内存分布的信息
end
整个加载过程基本分为三个步骤:
合法加测
解析Mach-O文件头信息,将segments 的具体信息 构建到image 的实例中
添加image 到管理容器
根据 dyld的源代码的粗略分析, 更多信息需要分析 xnu 内核代码。
参考
ObjC runtime 源代码
dyld 源代码
《Mac OSX and iOS Internals》
原文链接:http://blog.tingyun.com/web/article/detail/1346
dyld 加载 Mach-O的更多相关文章
- Mac-O文件加载的全过程(一)
在Mac的开发中, 有没有想过当我们点击可执行文件之后,Mac究竟做了什么事情才让我们的程序运行起来? 对于应用层开发人员或者普通的用户而言, 其实无需知道的这么详细:但是对于内核开发人员而言, 如果 ...
- mkimage工具 加载地址和入口地址 内核启动分析
第三章第二节 mkimage工具制作Linux内核的压缩镜像文件,需要使用到mkimage工具.mkimage这个工具位于u-boot-2013. 04中的tools目录下,它可以用来制作不压缩或者压 ...
- 动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)
section cmd 说明 举例 __text 主程序代码 __stubs 用于动态库链接的桩 __stub_helper 用于动态库链接的桩 __cstring 常亮字符串符号表描述信 ...
- Devices Tree加载流程
DT.IMG布局 hdr zImage Ramdisk.img DT.img 其中DT.img由DTBTOOL打包所有编译生成的dtb生成:布局如下: DT header dt_entry_0 dt_ ...
- 百度推出新技术 MIP,网页加载更快,广告呢?
我们在2016年年初推出了MIP,帮助移动页面加速(原理).内测数据表明,MIP页面在1s内加载完成.现在已经有十多家网站加入MIP项目,有更多的网站正在加入中.在我们收到的反馈中,大部分都提到了广告 ...
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...
- 高性能Javascript--脚本的无阻塞加载策略
Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理U ...
- 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)
首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...
- Bootstrap-Select 动态加载数据的小记
关于前端框架系列的可以参考我我刚学Bootstrap时候写的LoT.UI http://www.cnblogs.com/dunitian/p/4822808.html#lotui bootstrap- ...
随机推荐
- -Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HO 解决办法
最近在使用maven,项目测试的时候出现了这么一个错.-Dmaven.multiModuleProjectDirectory system property is not set. Check $M2 ...
- xib文件的加载方法
xib文件的加载方法 以UITableViewCell的cell为例 很多时候因为系统的cell无法满足我们的日常需求,我们都会自定义cell 因为cell的界面比较固定,所以通常都会选择用xib来描 ...
- Atitit 图像处理类库大总结attilax qc20
Atitit 图像处理类库大总结attilax qc20 1.1. 选择与组合不同的图像处理类库1 1.2. Halcon 貌似商业工具,功能强大.1 1.3. Openvc Openvc功能也是比 ...
- JavaScript高级编程 (2) - HTML 与 JavaScript
向HTML 页面中插入JavaScript 的主要方法,就是使用<script>元素.这个元素由Netscape 创造并在Netscape Navigator 2 中首先实现.后来,这个元 ...
- Git(最基本使用远程仓库:github)-V1.0
所有操作的根目录是:D:/zqzGit文件夹,这个目录也是git仓库 git bash清屏 clear 1.安装(略) 2.安装后记得配置: $ git config --global user ...
- Php基础知识测试题
一:选择题 1. LAMP具体结构不包含下面哪种(A ) A:Windows系统 如果是这个就是WMP B:Apache服务器 C:MySQL数据库 D:PHP语 ...
- ITTC数据挖掘系统(六)批量任务,数据查看器和自由文档
这一次带来了一系列新特新,同时我们将会从商业智能的角度讨论软件的需求 一. 批量任务向导 一个常用的需求是完成处理多个任务,可能是同一个需求以不同的参数完成多次,这类似批量分析某一问题:或者是不同的需 ...
- 微信扫描下载提示以及js判断用户手机系统
今天抽空也写一下这个教程吧,这里面涉及到就是一个APP的页面下载.公司有这个需求,让做一个页面,就是二维码扫描下载.一开始我做的版本是只能是通过浏览器来下载的,但是实际应用中,很多用户 ...
- IDDD 实现领域驱动设计-上下文映射图及其相关概念
上一篇:<IDDD 实现领域驱动设计-理解限界上下文> 距离上一篇有几天时间了,<实现领域驱动设计>第三章的内容都是围绕一个词-上下文映射图,我大概断断续续看了几天,总共看了两 ...
- 数据库日常维护-CheckList_02有关数据库备份检查
数据库备份是DB日常运维中最基本的也是最重要的工作,很多情况下都是做成作业形式实现自动化周期性的做全备.差异以及日志备份.那么,如果作业出现问题没有完成工作,我们可以设置自动报警如email被动提醒我 ...