遗留的问题
在上一篇文章中程序的加载上分析了程序加载的部分流程,其中一个将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
函数.