1. 程式人生 > >iOS App程式在呼叫main()之前做了那些事情?

iOS App程式在呼叫main()之前做了那些事情?

1、APP啟動時間
1)main之前的系統dylib(動態連結庫)和自身App可執行檔案的載入的時間
2)main之後執行didFinishLaunchingWithOptions:結束前的時間
2、main之前的載入過程
1)首先載入可執行檔案(自身app的所有.o檔案集合)
2)然後載入動態連結庫dyld,dyld是一個專門用來載入動態連結庫的庫
3)執行從dyld開始,dyld從可執行檔案的依賴開始,遞迴載入所有的依賴動態連結庫
4)動態連結庫包括:iOS中用到的所有系統的framework,載入OC runtime方法的libobjec,系統級別的libSystem,例如libdispatch(GCD)he libsystem_blocks(Block)
5)dyld:the dynamic link editor,所有動態連結庫和我們App的靜態庫.a和所有類檔案編譯後.o檔案,最終都由dyld載入到記憶體的
3、動態連結庫庫是相對於系統來講的
4、可執行檔案是相對於App本身來講的
5、每個app 都是以映象為單位進行載入的
1)映象(Mirroring)是冗餘的一種型別,一個磁碟上的資料在另一個磁碟上存在一個完全相同的副本即為映象。
2)映象是一種檔案儲存形式,可以把許多檔案做成一個映象檔案。
3)每個映象又都有個ImageLoader類來負責載入,一一對應的關係
6、framework 是動態連結庫和相應資源包含在一起的一個檔案結構
7、系統使用動態連結庫的好處
1)程式碼共用:很多程式都動態連結了這些lib,但它們在記憶體和磁碟中只有一份
2)易於維護:由於被依賴的lib是程式執行時才連結的,所以這些很容易更新,只要保證在程式執行之前,獲取最新lib即可
3)減少可執行檔案體積:相比靜態連結,動態連結在編譯時不需要打進去,所有可執行檔案的體積要小很多
8、動態連結庫的載入步驟具體分為5步
1)load dylibs image 讀取庫映象檔案
2)Rebase image 重定位映象
3)Bind image 組裝映象
4)Objc setup 設定物件
5)initializers 初始化
9、第一步又分為下面6個過程
1)分析所依賴的動態庫
2)找到動態庫的mach-o 檔案(我們知道Windows下的檔案都是PE檔案,同樣在OS X和iOS中可執行檔案是Mach-o格式的。)
3)開啟檔案
4)驗證檔案
5)在系統核心註冊檔案簽名
6)對動態庫的每一個segment呼叫mmap()
10、8.2,8.3
由於ASLR(address apace layout randomization)的存在,可執行檔案和動態連結庫在虛擬記憶體中的載入地址每次啟動都不固定,所以需要這兩步倆修復映象中的資源地址,來紙箱正確的地址
1)rabase 修復的是指當前映象記憶體的資源指標;bind指向的是映象外部的資源指標
2)rebase步驟先進行,需要把映象讀入記憶體,並以page為單位進行加密驗證,保證不會被篡改;bind 在其後進行,由於要查詢表符號表,來指向映象的資源;
11、8.4
1) 註冊objc類
2)把category的定義插入方法列表
3)保證每個selector唯一
12、8.5
0)以上三步屬於靜態調整(fix up),都是在修改__DATA segment中內容,從這裡開始動態調整,開始在堆和堆疊寫入內容
1)objc 的 + load 函式
2)C++的建構函式屬性函式 形如 attribute((contructor))void DoSomeInitializationWork()
3)非基本型別的C++靜態全域性變數的建立(通常是類或結構體)(non-trivial initializer)重大初始化
13、再次回顧整個呼叫順序
1)dyld 開始將程式二進位制檔案初始化
2)交由ImageLoader 讀取 image,其中包含了我們的類,方法等各種符號(Class、Protocol 、Selector、 IMP)
3)由於runtime 向dyld 綁定了回撥,當image載入到記憶體後,dyld會通知runtime進行處理
4)runtime 接手後呼叫map_images做解析和處理
5)接下來load_images 中呼叫call_load_methods方法,遍歷所有載入進來的Class,按繼承層次依次呼叫Class的+load和其他Category的+load方法
6)至此 所有的資訊都被載入到記憶體中
7)最後dyld呼叫真正的main函式
8)注意:dyld會快取上一次把資訊載入記憶體的快取,所以第二次比第一次啟動快一點