iOS-dyld加載流程

我們先來(lái)看看這個(gè)現(xiàn)象吧嬉橙。
新建一個(gè)工程,如下俺陋,分別添加c++函數(shù),和load方法洛史,運(yùn)行程序。


添加c++函數(shù)

重寫(xiě)load方法

查看結(jié)果


運(yùn)行結(jié)果

按我們一般的認(rèn)知酱吝,main函數(shù)才是程序的入口也殖,為什么會(huì)有方法在main之前就運(yùn)行呢?务热?忆嗜?這不是搞笑呢嗎?其實(shí)這都是有原因的崎岂,隆重請(qǐng)出今天的主角——dyld捆毫。

什么是dyld?

dyld(the dynamic link editor)是蘋(píng)果的動(dòng)態(tài)鏈接器冲甘,是蘋(píng)果操作系統(tǒng)的重要組成部分冻璃,在app被編譯打包成可執(zhí)行文件格式的Mach-O文件后,交由dyld負(fù)責(zé)連接损合,加載程序

所以 App的啟動(dòng)流程圖如下


image.png

由此可以看出省艳,其實(shí)在進(jìn)入main函數(shù)之前,還是有不少前戲的嫁审。那么我們就從控制臺(tái)最先打印的load方法入手吧跋炕。直接給load打個(gè)斷點(diǎn),查看一下堆棧信息:

image.png

我們會(huì)發(fā)現(xiàn)律适,是從dyld中的_dyld_start開(kāi)始的辐烂,所以需要去OpenSource下載一份最新dyld的源碼來(lái)進(jìn)行分析。

直接在源碼中搜索_dyld_start捂贿,可以看到不通架構(gòu)纠修,有不同的實(shí)現(xiàn),這里就只分析arm64厂僧,也就是真機(jī)的源碼哦扣草。

匯編源碼

如上圖,匯編前面在做一些準(zhǔn)備工作颜屠,最終會(huì)調(diào)用dyldbootstrap::start方法辰妙,源碼中搜索dyldbootstrap,找到它的命名空間,我覺(jué)得這里的命名空間可以理解為一個(gè)類(lèi),然后找到start方法

dyldbootstrap

start方法

通過(guò)注釋分析甫窟,前面是對(duì)dyld的準(zhǔn)備密浑,我們直接定位到dyld::_main,我們直接定位到dyld::_main函數(shù),注意這里的dyld::_main并非我們工程里的main函數(shù)粗井。
找到dyld::_main后會(huì)發(fā)現(xiàn)尔破,這這這太tm長(zhǎng)了吧街图,不想看了,嗚嗚嗚懒构。

image.png

額餐济,我還是簡(jiǎn)單總結(jié)一下吧。

【第一步:環(huán)境變量配置】:根據(jù)環(huán)境變量設(shè)置相應(yīng)的值以及獲取當(dāng)前運(yùn)行架構(gòu)
【第二步:共享緩存】:檢查是否開(kāi)啟了共享緩存痴脾,以及共享緩存是否映射到共享區(qū)域颤介,例如UIKit梳星、CoreFoundation等
【第三步:主程序的初始化】:調(diào)用instantiateFromLoadedImage函數(shù)實(shí)例化了一個(gè)ImageLoader對(duì)象赞赖,其中sniffLoadCommands函數(shù)時(shí)獲取Mach-O類(lèi)型文件的Load Command的相關(guān)信息,并對(duì)其進(jìn)行各種校驗(yàn)
【第四步:插入動(dòng)態(tài)庫(kù)】:遍歷DYLD_INSERT_LIBRARIES環(huán)境變量冤灾,調(diào)用loadInsertedDylib加載
【第五步:link 主程序】
【第六步:link 動(dòng)態(tài)庫(kù)】
【第七步:弱符號(hào)綁定】
【第八步:執(zhí)行初始化方法】遞歸遍歷實(shí)例化
【第九步:尋找主程序入口即main函數(shù)】:從Load Command讀取LC_MAIN入口前域,如果沒(méi)有,就讀取LC_UNIXTHREAD韵吨,這樣就來(lái)到了日常開(kāi)發(fā)中熟悉的main函數(shù)了

看到這好像和開(kāi)頭的問(wèn)題沒(méi)撒關(guān)系啊匿垄。搞什么飛機(jī),偏題了归粉?
問(wèn)題出在我偷懶了椿疗,我們倆看看第八步的具體實(shí)現(xiàn)吧。

image.png

進(jìn)入該方法
image.png

找到關(guān)鍵代碼runInitializers,找到其實(shí)現(xiàn)
image.png

繼續(xù)往下
image.png

找到關(guān)鍵代碼
image.png

這里主要有doInitializationnotifySingle 兩個(gè)函數(shù)糠悼,通過(guò)閱讀注釋?zhuān)杏X(jué)notifySingle 是類(lèi)似于通知的東西届榄,我們來(lái)驗(yàn)證一下是不是呢
notifySingle 函數(shù)

全局搜索notifySingle(函數(shù),其重點(diǎn)是(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());這句


image.png

找到如上關(guān)鍵代碼,搜索sNotifyObjCInit

image.png

發(fā)現(xiàn)只有賦值倔喂,沒(méi)有實(shí)現(xiàn)铝条,那追蹤一下是哪里賦值過(guò)來(lái)的呢。搜索registerObjCNotifiers
image.png

發(fā)現(xiàn)是這玩意賦值的_dyld_objc_notify_register
注意:_dyld_objc_notify_register的函數(shù)需要在libobjc源碼中搜索

然后繼續(xù)探索_dyld_objc_notify_register又是怎么調(diào)用過(guò)來(lái)的呢席噩?繼續(xù)在dyld源碼中搜索_dyld_objc_notify_register,發(fā)現(xiàn)找不到調(diào)用了班缰,哦嚯,就這么斷掉了悼枢?
作為要成為海賊王的男人埠忘,怎么能就這么斷掉呢?馒索?给梅?我們使用倒推大法,康康之前的堆棧信息双揪,發(fā)現(xiàn)是objcload_images方法調(diào)用的load方法动羽,

image.png

這個(gè)時(shí)候需要去objc源碼中搜索load_images啦,同樣可以在Opensource上下載渔期。
誒嘿运吓,找到這個(gè)逼了渴邦。

image.png

哈哈哈,這玩意- _dyld_objc_notify_register也跟著出來(lái)了拘哨。我們來(lái)理一理谋梭,
_objc_init調(diào)用_dyld_objc_notify_register,將load_images作為參數(shù)傳到了dyld::registerObjCNotifiers并賦值給了sNotifyObjCInit,然后notifySingle方法調(diào)用了sNotifyObjCInit倦青,清晰了清晰了瓮床。所以notifySingle是一個(gè)回調(diào)函數(shù)。
load函數(shù)加載

下面我們進(jìn)入load_images的源碼看看其實(shí)現(xiàn)产镐,以此來(lái)證明load_images中調(diào)用了所有的load函數(shù)

通過(guò)objc源碼中_objc_init源碼實(shí)現(xiàn)隘庄,進(jìn)入load_images的源碼實(shí)現(xiàn)

image.png

這里是通了,但好像又忽略了一個(gè)問(wèn)題癣亚,_objc_init又是哪里調(diào)用過(guò)來(lái)的呢丑掺?這個(gè)時(shí)候回到剛才提到的另一個(gè)方法doInitialization。偷個(gè)懶述雾,感興趣的朋友可以按這個(gè)探索一下街州。
_objc_init的源碼鏈:_dyld_start --> dyldbootstrap::start --> dyld::_main --> dyld::initializeMainExecutable --> ImageLoader::runInitializers --> ImageLoader::processInitializers --> ImageLoader::recursiveInitialization --> doInitialization -->libSystem_initializer(libSystem.B.dylib) --> _os_object_init(libdispatch.dylib) --> _objc_init(libobjc.A.dylib)

啟動(dòng)流程圖


image.png

這也就解釋了開(kāi)頭打印順序的問(wèn)題。

參考:http://www.reibang.com/p/db765ff4e36a

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末玻孟,一起剝皮案震驚了整個(gè)濱河市唆缴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌黍翎,老刑警劉巖面徽,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異玩敏,居然都是意外死亡斗忌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)旺聚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)织阳,“玉大人,你說(shuō)我怎么就攤上這事砰粹∵蠖悖” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵碱璃,是天一觀的道長(zhǎng)弄痹。 經(jīng)常有香客問(wèn)我,道長(zhǎng)嵌器,這世上最難降的妖魔是什么肛真? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮爽航,結(jié)果婚禮上蚓让,老公的妹妹穿的比我還像新娘乾忱。我一直安慰自己,他們只是感情好历极,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蹄葱,像睡著了一般图云。 火紅的嫁衣襯著肌膚如雪吮螺。 梳的紋絲不亂的頭發(fā)上鸠补,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天规惰,我揣著相機(jī)與錄音,去河邊找鬼贪磺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛刹前,可吹牛的內(nèi)容都是我干的喇喉。 我是一名探鬼主播拣技,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼过咬!你這毒婦竟也來(lái)了大渤?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤掸绞,失蹤者是張志新(化名)和其女友劉穎泵三,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體衔掸,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烫幕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敞映。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片较曼。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖振愿,靈堂內(nèi)的尸體忽然破棺而出捷犹,到底是詐尸還是另有隱情,我是刑警寧澤冕末,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布萍歉,位于F島的核電站,受9級(jí)特大地震影響档桃,放射性物質(zhì)發(fā)生泄漏枪孩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一藻肄、第九天 我趴在偏房一處隱蔽的房頂上張望蔑舞。 院中可真熱鬧,春花似錦嘹屯、人聲如沸攻询。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蜕窿。三九已至,卻和暖如春呆馁,著一層夾襖步出監(jiān)牢的瞬間桐经,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工浙滤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阴挣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓纺腊,卻偏偏與公主長(zhǎng)得像畔咧,于是被迫代替她去往敵國(guó)和親茎芭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容