iOS 面试

iOS:动态库的加载顺序

2020-07-09  本文已影响0人  笑出zhu声

在写 《iOS:load方法能不能被hook?》《iOS启动优化:App启动耗时在线监控与AppDelegate管控》 两篇文章时都提到了动态库的加载,由于主题的原因,没有详细介绍,有同学对这个比较感兴趣,今天我们就来研究下在iOS中动态库的加载顺序是什么样子的。

1.实验篇

我们先通过demo看下几种Case:

2.源码篇

上面我们通过几个实验对动态库的加载有个大概的影响,下面我们通过源码进一步了解动态库的加载(dyld源码,本文使用版本:dyld-635.2,篇幅问题,只展示部分代码)。
为了便于的过程,我们在上面demo中的位于子节点的dylibF库的load方法添加一个符号断点,获取下这个load方法的调用栈:

  #0    +[ClassF load]
  #1    load_images ()
  #2    dyld::notifySingle(dyld_image_states, ImageLoader const*, ImageLoader::InitializerTimingList*) ()
  #3    ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) ()
  #4    ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) ()
  #5    ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) ()
  #6    ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) ()
  #7    ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) ()
  #8    ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) ()
  #9    dyld::initializeMainExecutable() 
  #10   dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) ()
  #11   dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) ()
  #12   _dyld_start ()

_dyld_startdyldbootstrap::start使用汇编实现,我们重点看下dyld::_main开始的实现。

好了,我们通过实验和源码的方式了解到了动态库的加载顺序:1)先从当前image文件(可执行文件/动态库)的Load Commonds中获取动态库的信息(包括顺序,名字,路径等);2)然后循环加载它依赖的动态库;3)加载完后,再根据当前image依赖的动态库列表递归加载各自依赖的动态库。

3.填坑篇

文章开始我们就挖了一个坑:实验的方式是建立在“load方法的调用顺序当做是动态库的加载顺序”这一假设上的,那么这一假设成立吗?
从上文中+[ClassF load]的调用栈可知:load 方法的调用是在initializeMainExecutable()中,在link()之后,initializeMainExecutable()后又调用ImageLoader::runInitializers()ImageLoader::processInitializers(),我们看下代码:

dyld_main.png
上一篇下一篇

猜你喜欢

热点阅读