IMG_5596.JPG

应用加载原理

一、动静态库

库:可执行的二进制文件,能够被操作系统加载到内存

  • 静态库 (.a),静态链接,库有可能重复,浪费空间
  • 动态库(.so/.dll),动态链接,苹果大部分库为动态库,共享内存,早期热更新技术也是走动态库

    二、dyld

    流程图

    image.png

image.png
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)

音视频设备模块框架图.jpg

主流程2

  • initialize this image - 初始化所有images->load_images->赋值
  • map load -> map() -> cxx this objc的c++初始化
  • notifySingle :load()
  • cxx C++ kcobjcbuild

音视频设备模块框架图 (1).jpg

Q

  1. 类的加载 - 协议 属性 ro -> rw 慢速流程 -> 懒加载 -> 非懒加载
  2. map_images() 什么时候?
  3. load_images()load方法 - cxx + load + main
  4. dyld -> main
  5. wwdc 2017 dyld2 vs dyld3

    dyld2 vs dyld3

    WechatIMG34808.png

    _dyld_objc_notify_init

  • notifySingles -> NotifyObjCInit

    1. // _dyld_objc_notify_init
    2. void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
    3. {
    4. // record functions to call
    5. sNotifyObjCMapped = mapped;
    6. sNotifyObjCInit = init;
    7. sNotifyObjCUnmapped = unmapped;
    8. // call 'mapped' function with all images mapped so far
    9. try {
    10. notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
    11. }
    12. catch (const char* msg) {
    13. // ignore request to abort during registration
    14. }
    15. // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
    16. for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
    17. ImageLoader* image = *it;
    18. if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
    19. dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
    20. (*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
    21. }
    22. }
    23. }

  • image list 查看所有macho文件,第一个的地址0x000000001023123012中的1是pagezero,后面的值是随机值ASLR
  • iOS11 后dyld3,加载速度更快,闭包模式ClosureMode
    • 首先从共享缓存中找闭包对象,然后去验证
    • 再去缓存中找,验证
    • 没有的话就去创建mainClosure
    • 通过launch closure启动,启动成功设置变量true,拿到主程序main函数
  • 实例化主程序后,添加到AllImages中,因为不止一个macho,第一个是主程序
  • 如果有第三库,插入动态库_dyld_insert_libary,越狱才可配置
  • 链接动态库,递归加载macho(这里记录了时间,可以通过配置打印)到allImages中,修正aslr、非懒加载符号加载、弱引用符号加载,懒加载符号是在使用时加载的,
  • 链接主程序,绑定符号(非懒加载、弱符号)
  • 初始化主程序

image.png