初識(shí)dyld

目錄

前言

main before

dyld簡(jiǎn)介

dyld加載流程

總結(jié)


前言


對(duì)于一個(gè)程序的加載隙姿,我們看到的入口函數(shù)都是main.m里面的main函數(shù)茵烈,這讓我們很容易的認(rèn)為程序是從這里開(kāi)始執(zhí)行的。其實(shí)不然,在這之前,故事已經(jīng)悄悄展開(kāi)了...

main before

在main函數(shù)之前,究竟做了什么师坎?我們新建一個(gè)工程,在main.m文件里給我們的main函數(shù)打上斷點(diǎn)堪滨,探探究竟胯陋。

在main函數(shù)打斷點(diǎn)

此時(shí)我們可以看到,在main之前執(zhí)行了一個(gè)start函數(shù)袱箱,敲上bt指令查看遏乔,可以看到libdyld.dylib start,再敲上up指令发笔。

跟蹤start函數(shù)

這時(shí)我們看到dylib的start并不是我們想要的盟萨,有點(diǎn)失望......重新整整思路,我們會(huì)發(fā)現(xiàn)筐咧,load函數(shù)在main函數(shù)之前執(zhí)行鸯旁,馬上為load函數(shù)打下斷點(diǎn)探一探噪矛。

load函數(shù)斷點(diǎn)

在這斷點(diǎn)下量蕊,我們可以看到函數(shù)調(diào)用棧的調(diào)用順序,發(fā)現(xiàn)首先調(diào)用_dyld_start,馬上跟進(jìn)

_dyld_start的匯編

查看_dyld_start艇挨,我們看到調(diào)用的是dyldbootstrap這個(gè)類的start函數(shù)残炮,此時(shí)想要繼續(xù)探究就必須查看蘋(píng)果的dyld源碼(開(kāi)源),這里的版本是635.2缩滨。

dyld簡(jiǎn)介

dyld全名為dynamic loader势就。在程序啟動(dòng)運(yùn)行時(shí)會(huì)依賴很多系統(tǒng)動(dòng)態(tài)庫(kù),系統(tǒng)動(dòng)態(tài)庫(kù)會(huì)通過(guò)dyld(動(dòng)態(tài)加載器)(默認(rèn)是/usr/lib/dyld)加載到內(nèi)存中脉漏,系統(tǒng)內(nèi)核讀取程序可執(zhí)行文件信息做一些準(zhǔn)備工作苞冯,接著會(huì)將工作交給dyld。由于很多程序需要使用系統(tǒng)動(dòng)態(tài)庫(kù)侧巨,不可能在每個(gè)程序加載時(shí)都去加載所有的系統(tǒng)動(dòng)態(tài)庫(kù)舅锄,為了優(yōu)化程序啟動(dòng)速度和利用動(dòng)態(tài)庫(kù)緩存,iOS系統(tǒng)采用了共享緩存技術(shù)司忱,將所有系統(tǒng)庫(kù)(私有與公有)編譯成一個(gè)大的緩存文件皇忿,這就是dyld_shared_cache,該緩存文件存在iOS系統(tǒng)下的 /System/Library/Caches/com.apple.dyld/目錄下。

dyld加載流程

_dyld_start函數(shù)開(kāi)始設(shè)置相關(guān)信息坦仍,并在最后調(diào)用了_mian()函數(shù)鳍烁。

_dyld_start()

進(jìn)入_main()函數(shù),我們可以看到dyld加載的主要流程繁扎。

1.設(shè)置上下文信息幔荒,配置進(jìn)程是否受限

首先,調(diào)用setContext,設(shè)置上下文信息铺峭,包括后面需要調(diào)用的函數(shù)及傳入?yún)?shù)墓怀。然后,調(diào)用configureProcessRestrictions卫键,設(shè)置進(jìn)程是否受限傀履。


2.配置環(huán)境變量,獲取當(dāng)前運(yùn)行架構(gòu)

調(diào)用checkEnvironmentVariables莉炉,如果allowEnvVarsPath與allowEnvVarsPrint為空钓账,直接跳過(guò),否則調(diào)用processDyldEnvironmentVariable處理并設(shè)置環(huán)境變量絮宁。

3.檢查共享緩存是否映射到了共享區(qū)域

首先梆暮,調(diào)用 checkSharedRegionDisable 檢查是否開(kāi)啟共享緩存,在iOS中是必須開(kāi)啟的绍昂,接著調(diào)用 mapSharedCache函數(shù)啦粹,將共享緩存映射到共享區(qū)域。

4.加載可執(zhí)行文件窘游,生成一個(gè)ImageLoader 實(shí)例對(duì)象

調(diào)用 instantiateFromLoadedImage 函數(shù)實(shí)例化一個(gè) ImageLoader 對(duì)象唠椭。該函數(shù)先調(diào)用 isCompatibleMachO 來(lái)判斷文件的架構(gòu)是否和當(dāng)前的架構(gòu)兼容,然后調(diào)用 ImageLoderMachO::instantiateMainExecutable 來(lái)加載文件生成實(shí)例忍饰,并將 image 添加到全局 sAllImages 中贪嫂。


5.加載所有插入的庫(kù)

遍歷 DYLD_INSERT_LIBRARIES 環(huán)境變量,調(diào)用 loadInsertedDylib 加載艾蓝。


6.鏈接主程序

調(diào)用 link 鏈接主程序力崇。內(nèi)核調(diào)用的是ImageLoader::link 函數(shù)。


7.鏈接所有插入的庫(kù)赢织,執(zhí)行符號(hào)替換

對(duì) sAllimages (除了主程序的Image外)中的庫(kù)調(diào)用link進(jìn)行鏈接亮靴,然后調(diào)用 registerInterposing 注冊(cè)符號(hào)插入。


8.執(zhí)行初始化方法

initializeMainExecutable 執(zhí)行初始化方法于置,其中 +load 和 constructor 方法就是在這里執(zhí)行茧吊。 initializeMainExecutable 內(nèi)部先調(diào)用了動(dòng)態(tài)庫(kù)的初始化方法,后調(diào)用主程序的初始化方法俱两。

該函數(shù)依次調(diào)用了 runInitializers饱狂、processInitializers、recursiveInitialization宪彩、notifySingle休讳。也就是我們?cè)诤瘮?shù)調(diào)用棧里看到的順序

在notifySingle函數(shù)里我們找不到 load_images 的調(diào)用,但分析發(fā)現(xiàn)一個(gè)可疑的函數(shù)指針

此處調(diào)用了sNotifyObjCInit 尿孔,發(fā)現(xiàn) sNotifyObjCInit? 是在下面的位置賦值的俊柔。繼續(xù)尋找筹麸,可以找到調(diào)用該函數(shù)的位置。

當(dāng)我們繼續(xù)尋找誰(shuí)調(diào)用了_dyld_objc_notify_register()函數(shù)時(shí)雏婶,發(fā)現(xiàn)在dyld源碼里找不到物赶。從函數(shù)的定義來(lái)看,該接口是供 objc runtime 調(diào)用的留晚,我們可以在新工程里為 _dyld_objc_notify_register 下符號(hào)斷點(diǎn)查看酵紫。


這時(shí),打開(kāi)objc 源碼 查看_objc_init()函數(shù)错维。

看到_dyld_objc_notify_register()函數(shù)的第二個(gè)參數(shù)時(shí)奖地,我們找到了 load_images ,查看load_images()函數(shù)發(fā)現(xiàn)一個(gè)回調(diào) call_load_methods()赋焕,繼續(xù)查看call_load_methods()函數(shù)参歹,發(fā)現(xiàn)里面循環(huán)調(diào)用 call_class_loads(),這也就說(shuō)明為什么load函數(shù)比main函數(shù)先調(diào)用隆判。到這里犬庇,我們找到函數(shù)調(diào)用棧的所有函數(shù),接下來(lái)返回dyld侨嘀。


9.尋找主程序入口

調(diào)用 getEntryFromLC_MAIN臭挽,從 Load Command 讀取LC_MAIN入口,如果沒(méi)有LC_MAIN入口飒炎,就讀取LC_UNIXTHREAD埋哟,然后跳到入口處執(zhí)行笆豁,這樣就來(lái)到了我們熟悉的main函數(shù)處郎汪。

總結(jié)

上面對(duì)dyld加載大概走了一個(gè)流程,很多細(xì)節(jié)還沒(méi)探究闯狱。最后附上一張圖煞赢!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哄孤,隨后出現(xiàn)的幾起案子照筑,更是在濱河造成了極大的恐慌,老刑警劉巖瘦陈,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凝危,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡晨逝,警方通過(guò)查閱死者的電腦和手機(jī)蛾默,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捉貌,“玉大人支鸡,你說(shuō)我怎么就攤上這事冬念。” “怎么了牧挣?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵急前,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瀑构,道長(zhǎng)裆针,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任寺晌,我火速辦了婚禮据块,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘折剃。我一直安慰自己另假,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布怕犁。 她就那樣靜靜地躺著边篮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奏甫。 梳的紋絲不亂的頭發(fā)上戈轿,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音阵子,去河邊找鬼思杯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛挠进,可吹牛的內(nèi)容都是我干的色乾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼领突,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼暖璧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起君旦,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤澎办,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后金砍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體局蚀,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年恕稠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琅绅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谱俭,死狀恐怖奉件,靈堂內(nèi)的尸體忽然破棺而出宵蛀,到底是詐尸還是另有隱情,我是刑警寧澤县貌,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布术陶,位于F島的核電站,受9級(jí)特大地震影響煤痕,放射性物質(zhì)發(fā)生泄漏梧宫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一摆碉、第九天 我趴在偏房一處隱蔽的房頂上張望塘匣。 院中可真熱鬧,春花似錦巷帝、人聲如沸忌卤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驰徊。三九已至,卻和暖如春堕阔,著一層夾襖步出監(jiān)牢的瞬間棍厂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工超陆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牺弹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓时呀,卻偏偏與公主長(zhǎng)得像张漂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子退唠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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