程序的加载下

563

遗留的问题

在上一篇文章中程序的加载上分析了程序加载的部分流程,其中一个将runtimedyld关联在一起的一个重要函数

_dyld_objc_notify_register(&map_images, load_images, unmap_image);

只是看了load_images是在什么时候调用的. 遗留了下面几个问题

  1. load_images调用的时候做了什么呢?
  2. c++的构造函数是在什么时候调用的?
  3. dyld是怎么调用到main函数的呢?

load方法和c++构造函数是在什么时候调用的?

自定义一个c++ initializer,然后打断点,运行起来的时候的堆栈是什么样的 image.png 可以看到c++的构造函数是在doModInitFunction中调用过来的. 打开dyld源码,可以看到如下的代码. image.png 定位到notifySingle image.png 上述源码可以看到notifySingle的调用只有在传dyld_image_state_dependents_initialized的时候会调用sNotifyObjcInit, 其中sNotifyObjcInit指向runtimeload_images的方法. 如下是load_images的源码 image.png image.png image.png 可以看到load_images-->call_load_methods-->call_class_loads,在call_class_loads中调用load方法. 得出以下结论

  • 先调用load方法,再调用c++构造方法. 调用c++构造函数是在doInitialization中调用的.
  • load_images就是调用所有的load方法. load方法是不会被覆盖的,调用了每个类的load方法, 所以我们在重写load方法的时候,是不需要调用super load.

dyld怎么调用main

全局搜索_dyld_start, _dyld_start是由汇编代码编写的 image.png 从注释中可以看出当调用结束dyldbootstrap::start之后,就会调用main函数,那么我们debug看下是否如此呢? image.png 可以看到,register read之后,寄存器rax是存的main函数, 下面就是jump rax, 也就是调用main函数.