iOS開發-APP啟動main()調用之前的加載過程

main()調用之前的加載過程

App開始啟動后,系統首先加載可執行文件(自身App的所有.o文件的集合),然后加載動態鏈接庫dyld。
dyld是一個專門用來加載動態鏈接庫的庫。
dyld源碼鏈接
執行從dyld開始,dyld從可執行文件的依賴開始, 遞歸加載所有的依賴動態鏈接庫。

動態鏈接庫包括:
iOS 中用到的所有系統 framework
加載OC runtime方法的libobjc,
系統級別的libSystem,例如libdispatch(GCD)和libsystem_blocks (Block)。

其實無論對于系統的動態鏈接庫還是對于App本身的可執行文件而言,他們都算是image(鏡像),而每個App都是以image(鏡像)為單位進行加載的。

什么是image(鏡像)

1.executable可執行文件 比如.o文件。
2.dylib 動態鏈接庫 framework就是動態鏈接庫和相應資源包含在一起的一個文件夾結構。
3.bundle 資源文件 只能用dlopen加載,不推薦使用這種方式加載。

除了我們App本身的可行性文件,系統中所有的framework比如UIKit、Foundation等都是以動態鏈接庫的方式集成進App中的。

系統使用動態鏈接有幾點好處:

代碼共用:很多程序都動態鏈接了這些 lib,但它們在內存和磁盤中中只有一份。 易于維護:由于被依賴的 lib 是程序執行時才鏈接的,所以這些 lib 很容易做更新,比如libSystem.dylib 是 libSystem.B.dylib 的替身,哪天想升級直接換成libSystem.C.dylib 然后再替換替身就行了。 減少可執行文件體積:相比靜態鏈接,動態鏈接在編譯時不需要打進去,所以可執行文件的體積要小很多。


Mach-O鏡像加載.png

如上圖所示,不同進程之間共用系統dylib的_TEXT區,但是各自維護對應的_DATA區。

所有動態鏈接庫和我們App中的靜態庫.a和所有類文件編譯后的.o文件最終都是由dyld(the dynamic link editor),Apple的動態鏈接器來加載到內存中。每個image都是由一個叫做ImageLoader的類來負責加載(一一對應),那么ImageLoader又是什么呢?

什么是ImageLoader

image 表示一個二進制文件(可執行文件或 so 文件),里面是被編譯過的符號、代碼等,所以 ImageLoader 作用是將這些文件加載進內存,且每一個文件對應一個ImageLoader實例來負責加載。
兩步走: 在程序運行時它先將動態鏈接的 image 遞歸加載 (也就是上面測試棧中一串的遞歸調用的時刻)。 再從可執行文件 image 遞歸加載所有符號。

當然所有這些都發生在我們真正的main函數執行前。

動態鏈接庫加載的具體流程

動態鏈接庫的加載步驟具體分為5步:

1.load dylibs image 讀取庫鏡像文件
2.Rebase image
3.Bind image
4.Objc setup
5.initializers

1.load dylibs image

在每個動態庫的加載過程中, dyld需要:
1.分析所依賴的動態庫
2.找到動態庫的mach-o文件
3.打開文件
4.驗證文件
5.在系統核心注冊文件簽名
6.對動態庫的每一個segment調用mmap()
通常的,一個App需要加載100到400個dylibs, 但是其中的系統庫被優化,可以很快的加載。

針對這一步驟的優化有:
1.減少非系統庫的依賴
2.合并非系統庫
3.使用靜態資源,比如把代碼加入主程序

2.rebase/bind

由于ASLR(address space layout randomization)的存在,可執行文件和動態鏈接庫在虛擬內存中的加載地址每次啟動都不固定,所以需要這2步來修復鏡像中的資源指針,來指向正確的地址。

rebase修復的是指向當前鏡像內部的資源指針;
而bind指向的是鏡像外部的資源指針。

rebase步驟先進行,需要把鏡像讀入內存,并以page為單位進行加密驗證,保證不會被篡改,所以這一步的瓶頸在IO。
bind在其后進行,由于要查詢符號表,來指向跨鏡像的資源,加上在rebase階段,鏡像已被讀入和加密驗證,所以這一步的瓶頸在于CPU計算。

//通過命令行可以查看相關的資源指針:
xcrun dyldinfo -rebase -bind -lazy_bind myApp.App/myApp

優化該階段的關鍵在于減少__DATA segment中的指針數量。

可以優化的點有:

1.減少Objc類數量, 減少selector數量
2.減少C++虛函數數量
3.轉而使用swift stuct(其實本質上就是為了減少符號的數量)

3.Objc setup

這一步主要工作是:
1.注冊Objc類 (class registration)
2.把category的定義插入方法列表 (category registration)
3.保證每一個selector唯一 (selctor uniquing)
4.由于之前2步驟的優化,這一步實際上沒有什么可做的。

4.initializers

以上三步屬于靜態調整(fix-up),都是在修改__DATA segment中的內容,而這里則開始動態調整,開始在堆和堆棧中寫入內容。 在這里的工作有:

1.Objc的+load()函數
2.C++的構造函數屬性函數 形如attribute((constructor)) void DoSomeInitializationWork()
3.非基本類型的C++靜態全局變量的創建(通常是類或結構體)(non-trivial initializer) 比如一個全局靜態結構體的構建,如果在構造函數中有繁重的工作,那么會拖慢啟動速度
Objc的load函數和C++的靜態構造函數采用由底向上的方式執行,來保證每個執行的方法,都可以找到所依賴的動態庫。

1).dyld 開始將程序二進制文件初始化
2).交由 ImageLoader 讀取 image,其中包含了我們的類、方法等各種符號
3).由于 runtime 向 dyld 綁定了回調,當 image 加載到內存后,dyld 會通知 runtime 進行處理
4).runtime 接手后調用 mapimages 做解析和處理,接下來 loadimages 中調用 callloadmethods 方法,遍歷所有加載進來的 Class,按繼承層級依次調用 Class 的 +load 方法和其 Category 的 +load 方法

至此
至此,可執行文件中和動態庫所有的符號(Class,Protocol,Selector,IMP,…)都已經按格式成功加載到內存中,被 runtime 所管理,再這之后,runtime 的那些方法(動態添加 Class、swizzle 等等才能生效)。

整個事件由 dyld 主導,完成運行環境的初始化后,配合 ImageLoader 將二進制文件按格式加載到內存, 動態鏈接依賴庫,并由 runtime 負責加載成 objc 定義的結構,所有初始化工作結束后,dyld 調用真正的 main 函數。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容