上一篇文章咱們講到了啓動優化須要的一些理論知識,這篇文章咱們講一下從exec()到main()系統幫咱們作了哪些操做。緩存
exec()函數是一個系統調用,當啓動一個應用程序的時候,系統內核把應用映射到新的地址空間,且每次起始位置都是隨機的(由於使用了ASLR),並將起始位置到0x000000這段範圍的進程權限都標記爲不可讀寫不可執行。安全
首先,內核加載動態連接庫的幫助程序Dyld,讓Dyld來啓動應用的進程。Dyld的工做是:bash
應用所依賴的dylib文件可能會依賴其它的dylib,因此dyld加載dylib的過程是一個遞歸的調用過程。ide
在加載完全部依賴的dylib後,它們是彼此獨立的,咱們須要將它們綁在到一塊兒,這個過程就是修復。由於代碼簽名的存在,咱們沒法修復指令,那麼就不能讓一個dylib調用另外一個dylib,這時須要加載更多的中間層。函數
現代的code-gen被稱爲動態PIC(位置無關代碼),能夠加載到該地址上,而且是動態的,也就是說地址被間接的分配了。當調用發生時,code_gen會在__DATA段中建立一個指向被調用者的指針,而後加載該指針並跳轉過去。優化
因此dyld作的事情就是修正(fix-up)指針和數據,Fix-up有兩種類型,rebasing(重設地址)和binding(綁定)。spa
Rebasing指的是在鏡像內調整指針,Binding指的是在鏡像外調整指針。指針
能夠在任何二進制文件上使用dyldinfo指令來查看全部的修復:code
在過去,dyld會把dylib加載到指定的地址,全部指針和數據對於代碼來講都是對的,dyld無需作任何fix-up。現在使用了ASLR會將dylib加載到新的隨機地址,這個隨機地址跟代碼和數據指向的舊地址會有誤差,dyld須要修正這個誤差(slide),Rebasing就是將dylib內部的指針地址都加上這個偏移量,計算方法以下:cdn
Slide = actual_address - preferred_address
複製代碼
當咱們重設地址時,實際上在全部的Data頁面上都產生了錯誤,而後對頁面進行修改,就會產生COW(寫入時複製),因此重設地址有時會很是昂貴。這可能會產生I/O瓶頸,但由於rebase的順序是按地址排列的,因此從內核的角度來看這是個有次序的任務,它會進行預讀,減小I/O消耗。
下期預告:iOS啓動優化實踐篇
關注公衆號,獲取更多文章內容