应用的加载流程-01

194 阅读3分钟

一、dyld---动态连接器

mach-o:文件格式(包括可执行文件、目标文件、静态库、动态库、dyld) 我们程序中的.m、.h、.cpp、.swift文件这些文件在生成可执行文件的之前需要经多很多过程

会经过预编译(主要是处理源代码中#开头的预编译的命令,如:#import、#include,将包含的文件插入到指定的位置,还会替换宏定义、删除注释)

编译--进行词法分析、语法分析、语义分析,会生相应的汇编代码文件

汇编--编译成机器指令,就生成.o文件

链接--静态链接和动态链接

静态库的本质是.o文件的集合

动态库是一个已经链接完全的镜像image(镜像image:用来表示任意一种类型的可执行文件,如可执行文件、dylib、bundle)

当代码经过静态链接之后不会存在静态库

1、dyld---动态连接器 app启动的时候是想从一个exec()这个函数开始的, 系统会调用exec()这个函数, 调用完这个函数就会给程序分配内存、创建进程, 然后就会把app对应的可执行文件加载进内存, 再将dyld加载到内存, dyld就会进行动态链接

2.dyld具体的工作

a.递归加载可执行文件所有依赖的动态库
b.rebase和binding
c.掉起main

3.我们通过load()方法查看堆栈信息(load()方法时在main放大之前调用的)

我们在load()方法打断点,在控制台输入bt,就能获取堆栈信息

dyld就是一个程序、也是开源的

dyld是从_dyld_start开始的,我们在dyld源码中找到_dyld_start,_dyld_start是用汇编写的,我们可以根据堆栈信息查看,他是去调用dyldbootstrap 里面start()的函数 图片.png 图片.png 在start()函数里面,这里是为调用main()函数做了准备,就可以调用main()函数了 图片.png 进入_main()函数后,我们看下面流程图 dyld流程分析图.png

通过流程图我们重点研究initializeMainExecutable如何初始化的

二、initializeMainExecutable初始化的

图片.png 图片.png 在静态库初始化之后还会为我们主可执行文件进行初始化 图片.png 我们主要看runInitializers()这个方法 图片.png 继续看runInitializers()这个方法processInitializers里recursiveInitialization() 图片.png 这些初始化都需要依赖runtime、objc 图片.png 我们一步一步找notifySingle()函数的实现,他这里走了这个分支 图片.png 最后的方法就是_dyle_objc_notify_register(),但是在dyld文件中找不到这个方法的调用,我们就知道是使用了runtime的API,他就是在_objc_init()中调用的 图片.png 堆栈信息调用顺序 图片.png

libsystem(动态库)要在第一个初始化,libsystem里面会初始化libdispath,在libdispath里面会初始化objc_init,在objc_init会调用_dyle_objc_notify_register(&map_images,load_images, unmap_image)————这些就是dyld递归加载可执行文件依赖的动态库

libsystem -> libdispath -> objc_init -> _dyle_objc_notify_register(&map_images,load_images, unmap_image)

为什么load()方法会在main()方法之前调用,就是因为传递了load_images(镜像文件)

&map_images,load_images的详情请见下节内容