遗留的问题
在上一篇文章中程序的加载上分析了程序加载的部分流程,其中一个将runtime和dyld关联在一起的一个重要函数
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
只是看了load_images是在什么时候调用的. 遗留了下面几个问题
load_images调用的时候做了什么呢?c++的构造函数是在什么时候调用的?dyld是怎么调用到main函数的呢?
load方法和c++构造函数是在什么时候调用的?
自定义一个c++ initializer,然后打断点,运行起来的时候的堆栈是什么样的
可以看到
c++的构造函数是在doModInitFunction中调用过来的. 打开dyld源码,可以看到如下的代码.
定位到
notifySingle
上述源码可以看到
notifySingle的调用只有在传dyld_image_state_dependents_initialized的时候会调用sNotifyObjcInit, 其中sNotifyObjcInit指向runtime中load_images的方法. 如下是load_images的源码
可以看到
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是由汇编代码编写的
从注释中可以看出当调用结束
dyldbootstrap::start之后,就会调用main函数,那么我们debug看下是否如此呢?
可以看到,
register read之后,寄存器rax是存的main函数, 下面就是jump rax, 也就是调用main函数.