main之前执行的方法

Objective-C中在通过定义一个+load()方法,让+load()方法在所有OC对象创建前被执行,同时也会在main函数执行前执行。一般情况下我们使用+load()方法进行一些hook、实现一些全局初始化的逻辑。

除了建立C++全局对象、实现OC类的+load方法来进行一些全局的初始化逻辑外,我们还可以定义带有特殊标志的C函数来实现main函数执行前以及main函数执行完毕后的处理逻辑

//main函数执行前被执行的函数

__attribute__((constructor))

//main函数执行完毕后被执行的函数

__attribute__((destructor))

代码实例
输出结果

通过输出结果可以确定:

1、带有特殊标识__attribute__((constructor))的方法会在main方法执行前执行;

2、带有特殊标识__attribute__((destructor))的方法会在main方法执行后执行;

main函数执行前发生了些什么呢?

操作系统在启动一个程序时,内核会为程序创建一个进程空间,并且会为进程创建一个主线程,主线程会执行各种初始化操作,完成后才开始执行我们在程序中定义的main函数

也就是说main不是第一个执行的函数,在main之前还会执行一系列的方法

_objc_init符号断点

通过设置_objc_init符号断点,然后结合bt命令查看在_objc_init之前发生了哪些事情(启动项目,断点到来之后,在控制台输入bt,会出现如下结果)

bt输出内容

看到栈底的dyldbootstrap::start()方法,继而调用了dyld::_main()方法,其中完成了递归加载动态库过程,由于libSystem默认引入,栈中出现了libSystem_initializer的初始化方法。

可以看到_objc_init调用顺序,先libSystem_initializer调用libdispatch_init,再到_objc_init初始化runtime.

runtime初始化后不会闲着,在_objc_init中注册了几个对象,从dyld这里接手几个活,其中包括初始化相应依赖库里的类结构,调用依赖库里所有load方法。

initializer方法是最后调用的,当initializer方法被调用前dyld会通知runtime进行类结构初始化,然后再通知调用+load方法,这些目前都发生在main函数前,但是由于lazy bind机制,依赖库多数都是在使用时才进行bind,所以这些依赖库的类结构初始化都是发生在程序里第一次使用到该依赖库时才进行

dyld

系统先读取App的可执行文件(Mach-O文件),从里面获得dyld的路径,然后加载dyld,dyld去初始化运行环境

1、dyld将我们可执行文件以及插入的lib加载进内存,生成对应的image

2、对上面生成的image进行链接。其主要有对image进行load(加载)、rebase(基地址复位),bind(外部符号绑定)

3、这一步主要是调用所有image的initalizer方法进行初始化。这里的initalizers方法并非名为Initalizers的方法,而是C++静态对象初始化构造器,atribute(constructor)进行修饰的方法,在ImageLoader类中initializer函数指针锁指向该初始化方法的地址

可以在程序中设置环境变量DYLD_PRINT_INITIALIZERS为1来打印出程序的各种依赖库的initializer方法


ImageLoader

这个image不是图片的意思,它大概表示一个二进制文件(可执行文件或so文件),里面是被编译过的符号、代码等,所以imageLoader作用是将这些文件加载进内存,且每一个文件对应一个imageLoader实例来负责加载

1.在程序运行时它先将动态链接的image递归加载(也就是上面ImageLoader的递归调用)

2.再从可执行文件image递归加载所有符号

runtime与load

libSystem是若干个系统lib的集合,所以它只是一个容器lib而已,而且它也是开源的,里面实质上就是一个文件: init.c 由libSystem_initializer逐步调用到了_objc_init,这里就是objc和runtime的初始化入口。

除了runtime环境的初始化外,_objc_init中绑定了新image被加载后的callback

load方法加断点后的调用堆栈

通过调用堆栈可以清晰的知道main之前整体的调用次序:

1.dyld开始将程序二进制文件初始化

2.交由imageLoader读取image,其中包含了我们的类,方法等各种符号

3.由于runtime向dyld绑定了回调,当image加载到内存后,dyld会通知runtime进行处理

4.runtime接手后调用map_images做解析和处理,接下来load_images中调用call_load_methods方法,遍历所有加载进来的Class,按继承层级依次调用Class的+load方法和Category的+load方法。

至此,可执行文件中和动态库所有的符号(Class, Protocol,Selector,IMP,...)都已经按格式成功加载到内存中,被runtime所管理,再这之后,runtime的那些方法(动态添加Class,swizzie等才能生效)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 228,197评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,415评论 3 415
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,104评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,884评论 1 309
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,647评论 6 408
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,130评论 1 323
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,208评论 3 441
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,366评论 0 288
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,887评论 1 334
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,737评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,939评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,478评论 5 358
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,174评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,586评论 0 26
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,827评论 1 283
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,608评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,914评论 2 372

推荐阅读更多精彩内容