dyld加载应用启动原理详解

本文详细探讨了iOS应用在调用main()函数之前的加载过程,主要涉及dyld动态链接器的工作原理。从dyld_bootstrap::start开始,通过分析dyld源码,了解了mach-o文件头部信息的读取、环境变量设置、库的加载和链接、初始化函数的执行等步骤,揭示了程序启动前的幕后工作,为理解APP启动性能优化提供了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们都知道APP的入口函数是main(),而在main()函数调用之前,APP的加载过程是怎样的呢?接下来我们一起来分析APP的加载流程。

一、利用断点进行追踪

  • 首先我们创建一个工程,什么代码都不写,在main()函数处进行断点,会看到情况如下图:

     

    01

  1. 通过上图我们可以看到,在调用堆栈中,我们只看到了star和main,并开启了主线程,其它的什么都看不到。那要怎么才能看到调用堆栈详细点的信息了?我们都知道,有一个方法比main()函数调用更早,那就是load()函数,此时在控制器中写一个load函数,并断点运行,如下图:

02

  1. 通过上图,我们看到了比较详细的函数调用顺序,从第13行的_dyld_start到第3行的dyld:notifySingle,频率出现最多的就是这个dyld的家伙,那么dyld是什么?它在做什么?简单来说dyld是一个动态链接器,用来加载所有的库和可执行文件。接下来我们将通过图2的调用关系,去追踪dyld到底在什么?

二、 dyld加载流程分析

1. 首先下载dyld源码

2. 打开dyld源码工程,根据图2的第12行dyldbootstrap:start为关键字搜索dyldbootstrap中调用的start方法,如下图:

 

3. 该方法源码如下,接下来我们对该方法的重点部分进行分析:

uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], intptr_t slide)
{
    // 读取macho文件的头部信息
    const struct macho_header* dyldsMachHeader =  (const struct macho_header*)(((char*)&_mh_dylinker_header)+slide);
    
    // 滑块,设置偏移量,用于重定位
    if ( slide != 0 ) {
        rebaseDyld(dyldsMachHeader, slide);
    }
    
    uintptr_t appsSlide = 0;
        
    // 针对偏移异常的监测
    dyld_exceptions_init(dyldsMachHeader, slide);
    
    // 初始化machO文件
    mach_init();

    // 设置分段保护,这里的分段下面会介绍,属于machO文件格式
    segmentProtectDyld(dyldsMachHeader, slide);
    
    //环境变量指针
    const char** envp = &argv[argc+1];
    
    // 环境变量指针结束的设置
    const char** apple = envp;
    while(*apple != NULL) { ++apple; }
    ++apple;

    // 在dyld中运行所有c++初始化器
    runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple);
    
    // 如果主可执行文件被链接-pie,那么随机分配它的加载地址
    if ( appsMachHeader->flags & MH_PIE )
        appsMachHeader = randomizeExecutableLoadAddress(appsMachHeader, envp, &appsSlide);
    
    // 传入头文件信息,偏移量等。调用dyld的自己的main函数(这里并不是APP的main函数)。
    return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple);
}

  • 3.1 函数的参数中我们看到有一个macho_header的参数,这是一个什么东西呢?Mach-O其实是Mach Object文件格式的缩写,是mac以及iOS中的可执行文件格式,并且有自己的文件格式目录,苹果给出的mach文件如下图:

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值