dyld 載入 Mach-O,dyld載入mach-o

來源:互聯網
上載者:User

dyld 載入 Mach-O,dyld載入mach-o

➠更多技術乾貨請戳:聽雲部落格

前言

最近看 ObjC的runtime 是怎麼實現 +load 鉤子函數的實現。進而引申分析了 dyld 處理 Mach-O 的這部分機制。

1.簡單分析 Mach-O 在dyld 中是如何被載入到記憶體中的;

2.分析了 +load 的 特殊載入時機;

+ load

的調用棧告訴我們哪些函數被調用了。

dyld 是Apple 的動態連結器;在 xnu 核心為程式啟動做好準備後,就會將 PC 控制權交給 dyld 負責剩下的工作 (dyld 是運行在 使用者態的, 這裡由 核心態 切到了使用者態)。

每當有新的鏡像載入之後,都會執行 load-images 方法進行回調,這裡的回調是在整個ObjC runtime 初始化時 -objc-init 註冊的 :

有新的鏡像被 map 到 runtime 時,調用 load-images 方法,並傳入最新鏡像的資訊列表 infoList:

這裡的鏡像就是 一些 System framework 的二進位。

進入 函數 load-images-nolock 尋找 load 函數

調用 prepare-load-methods 對 load 方法的調用進行準備(將需要調用 load 方法的類添加到一個列表中)

調用 -getObjc2NonlazyClassList 擷取所有的類的列表之後,會通過 remapClass 擷取類對應的指標,然後調用 schedule-class-load 遞迴地 將當前類和沒有調用 + load 父類進入列表。

在執行 add-class-to-loadable-list(cls) 將當前類加入載入列表之前,會先把父類加入待載入的列表,保證父類在子類前調用 load 方法。

在將鏡像載入到運行時、對 load 方法的準備就緒,執行 call-load-methods,開始調用 load 方法:

其中 call-class-loads 會從一個待載入的類列表 loadable-classes 中尋找對應的類,然後找到 @selector(load) 的實現並執行。

分析到這裡,已經能得知 load 函數是如何被調用的。

接下來分析 dyld 這部分怎麼載入鏡像的

1.1 資料結構

mach-o 檔案頭 操作。 

1.2 ImageLoader

每一個載入的 Mach-O 檔案都會存在這樣一個ImageLoader 的 執行個體,可以看出 這裡ImageLoader是一個抽象類別,每一種具體的Mach-O 檔案都會繼承 ImageLoader類, 繼承關係 如:

 在載入時會根據Mach-O的格式不同選擇產生不用的執行個體。

1.3 -main

在調用-main 函數之後,做了一下幾件事情:

  1. 選擇運行環境(iOS 模擬器)

  2. 初始化資料、設定全域變數、上下文資訊

  3. 檢查檔案是否Restricted

走完這些流程,就會調用 instantiateFromLoadedImage 函數,開始載入Mach-O 並且執行個體化 為 ImageLoader。

1.4 instantiateFromLoadedImage

這個函數做了三件事情: 

  1. 檢查Mach-O 檔案是否合法 

  2. 初始化 ImageLoader 執行個體 

  3. 調用addImage 函數添加 初始化後的執行個體到管理模組中

1.5 isCompatibleMachO

Mach-O 檔案的合法性檢查: 

  1. mach-header 中的 cputype與當前啟動並執行CPU 版本是否支援

  2. mach-header 中的 subtype 在該CPU 架構下的所有版本都可以支援

cputype 就是CPU 平台, x86,ARM ,POWERPC 等, 而subtype 就是同一個平台下的不同版本, 例如:arm7,arm7.

1.6 ImageLoaderMachO: : instantiateMainExecutable

該函數主要通過 sniffLoadCommands 函數來判斷 Mach-O 檔案是否是壓縮過的,然後分別 選擇不同的 子類執行個體化。 

1.7 sniffLoadCommands

這個函數主要做兩件事情 

  1. 判斷Mach-O檔案是classic的還是compressed的。 

  2. 擷取mach-O檔案的segment的數量。

1.8 ImageLoaderMachOClassic: :instantiateMainExecutable

classic 與 compressed 的初始化大同小異,先分析Classic 的實現 

可以看到載入的核心代碼 還在 instantiateStart 函數中

1.9 instantiateStart

這裡仍然沒有出現載入的核心代碼,只是根據之前獲得的資料申請分配了記憶體,並計算 segments的 指標。 ImageLoaderMachOClassic 的建構函式才是載入 的核心邏輯。

2.0 ImageLoaderMachOClassic

根據Mach-O 檔案 segments 將資料載入到 記憶體中, 任何返回 調用 addImage 函數。

2.1 addImage

這個函數只是做了資料更新 

  1. 將image 添加到管理容器中

  2. 更新了記憶體分布的資訊

end

整個載入過程基本分為三個步驟:

  1. 合法加測

  2. 解析Mach-O檔案頭資訊,將segments 的具體資訊 構建到image 的執行個體中

  3. 添加image 到管理容器

根據 dyld的原始碼的粗略分析, 更多資訊需要分析 xnu 核心代碼。

參考

ObjC runtime 原始碼

dyld 原始碼

《Mac OSX and iOS Internals》

原文連結:http://blog.tingyun.com/web/article/detail/1346

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.