应用加载原理
一、动静态库
库:可执行的二进制文件,能够被操作系统加载到内存
dyld库中:
- _dyld_start 汇编 -> call dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)
- 找到namespace dyldbootstrap C++的名称空间 -> start -> dyld::main()
_os_object_init(libdispatch库) -> _objc_init(libobjc)
_dyld_objc_notify_register
- _dyld_objc_notify_register(&map_images, load_images, upmap_image)
- map_images回调,镜像加载到内存的时间不固定,所有镜像加载完毕,该函数会回调,然后调用doModInitFunction(_dyld)
主流程1
- dyld start——-libsystem——-libdispatch——GCD环境准备———libObjc(_objc_init)
主流程2
- initialize this image - 初始化所有images->load_images->赋值
- map load -> map() -> cxx this objc的c++初始化
- notifySingle :load()
- cxx C++ kcobjcbuild
Q
- 类的加载 - 协议 属性 ro -> rw 慢速流程 -> 懒加载 -> 非懒加载
- map_images() 什么时候?
- load_images()load方法 - cxx + load + main
- dyld -> main
- wwdc 2017 dyld2 vs dyld3
dyld2 vs dyld3
_dyld_objc_notify_init
notifySingles -> NotifyObjCInit
// _dyld_objc_notify_init
void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
// record functions to call
sNotifyObjCMapped = mapped;
sNotifyObjCInit = init;
sNotifyObjCUnmapped = unmapped;
// call 'mapped' function with all images mapped so far
try {
notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
}
catch (const char* msg) {
// ignore request to abort during registration
}
// <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
ImageLoader* image = *it;
if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
}
}
}
- image list 查看所有macho文件,第一个的地址0x000000001023123012中的1是pagezero,后面的值是随机值ASLR
- iOS11 后dyld3,加载速度更快,闭包模式ClosureMode
- 首先从共享缓存中找闭包对象,然后去验证
- 再去缓存中找,验证
- 没有的话就去创建mainClosure
- 通过launch closure启动,启动成功设置变量true,拿到主程序main函数
- 实例化主程序后,添加到AllImages中,因为不止一个macho,第一个是主程序
- 如果有第三库,插入动态库_dyld_insert_libary,越狱才可配置
- 链接动态库,递归加载macho(这里记录了时间,可以通过配置打印)到allImages中,修正aslr、非懒加载符号加载、弱引用符号加载,懒加载符号是在使用时加载的,
- 链接主程序,绑定符号(非懒加载、弱符号)
- 初始化主程序