重学OC第十篇:dyld加载

前言

@interface ViewController : UIViewController
@end
@implementation ViewController
+ (void)load
{
   
    NSLog(@"load");
}
@end

int main(int argc, char * argv[]) {
   
	NSLog(@"main");
    NSString * appDelegateClassName;
    @autoreleasepool {
   
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

//__attribute__((constructor))编译器constructor属性,会让函数在main()之前执行
__attribute__((constructor)) static void abc() {
   
    printf("abc\n");
}

运行结果如下

2020-09-26 14:26:35.519913+0800 RuntimeLeaning[2704:1529828] load
abc
2020-09-26 14:26:35.521017+0800 RuntimeLeaning[2704:1529828] main

可以看到打印顺序为load->abc->main, 在load方法中打上断点,然后运行

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
  * frame #0: 0x0000000100bcded4 RuntimeLeaning`+[ViewController load](self=ViewController, _cmd="load") at ViewController.m:23:5
    frame #1: 0x000000020b669ffc libobjc.A.dylib`call_load_methods + 184
    frame #2: 0x000000020b66be54 libobjc.A.dylib`load_images + 180
    frame #3: 0x0000000100fc2390 dyld`dyld::notifySingle(dyld_image_states, ImageLoader const*, ImageLoader::InitializerTimingList*) + 444
    frame #4: 0x0000000100fd4380 dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 440
    frame #5: 0x0000000100fd33dc dyld`ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 136
    frame #6: 0x0000000100fd3498 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 84
    frame #7: 0x0000000100fc26d8 dyld`dyld::initializeMainExecutable() + 220
    frame #8: 0x0000000100fc72a0 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 4304
    frame #9: 0x0000000100fc1044 dyld`_dyld_start + 68
(lldb) 

从这个堆栈信息中可以知道在最开始先调用的是dyld的_dyld_start方法,dyld是苹果的动态链接器, 是苹果操作系统一个重要组成部分,在系统内核做好程序准备工作之后,交由dyld负责余下的工作。

dyld源码下载:dyld源码,下面使用750.6版本。

dyld源码分析

一、dyld汇编入口点:__dyld_start

在dyld源码中搜索_dyld_start,发现只有__dyld_start, 存在于dyld.xcconfig和dyldStartup.s中, dyld.xcconfig从后缀看是个配置文件, 里面有一段如下:

ENTRY[sdk=*simulator*]     = -Wl,-e,_start_sim      //模拟器
ENTRY[sdk=iphoneos*]       = -Wl,-e,__dyld_start    //真机
ENTRY[sdk=macosx*]         = -Wl,-e,__dyld_start	//mac

再看dyldStartup.s从后缀看是汇编文件,名字涵义就是dyld启动, 下面是其中arm64的部分代码

__dyld_start:
	......
	// call dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)
	bl	__ZN13dyldbootstrap5startEPKN5dyld311MachOLoadedEiPPKcS3_Pm
	mov	x16,x0                  // save entry point address in x16
	ldr     x1, [sp]
	cmp	x1, #0
	b.ne	Lnew
	// LC_MAIN case, set up stack for call to main()
Lnew:	mov	lr, x1		    // simulate return address into _start in libdyld.dylib
	......
#if __arm64e__   	//用于A12芯片组,从2018年XS、XS MAX、XR开始
	braaz   x16		//带指针验证,转到寄存器x16
#else
	br      x16
#endif

从上面可以看到,先是调用了dyldbootstrap::start,后面如果x1不等于0就会进入程序的main()函数。

//  This is code to bootstrap dyld.  This work in normally done for a program by dyld and crt.
//  In dyld we have to do this manually.
uintptr_t start(const dyld3::MachOLoaded* appsMachHeader, int argc, const char* argv[],
				const dyld3::MachOLoaded* dyldsMachHeader, uintptr_t* startGlue)
{
   
    dyld3::kdebug_trace_dyld_marker
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值