秉心識本源,於事少凝滯。– 《信行遠修水筒》
瞭解一個系統的唯一途徑就是去閱讀原始碼
要想完全的瞭解一個系統唯一的方法就是去閱讀這個系統的原始碼實現!這個原則對於一個iOS程式設計師也是如此。很幸運的是我們現在處於一個開原始碼迸發的美好時代(這裡要感謝理查·馬修·斯托曼以及他的GNU計劃),很多優秀的庫都以原始碼的形式呈現給大家,甚至連iOS這種封閉的系統也迫於某種壓力開放了部分原始碼(雖然開放的部分並不一定和真實的相同),這也已經足以給了我們很多熱情去窺探其內部的一些實現機制。目前網路上也有非常多的基於蘋果的開源而介紹OC2.0的runtime原理以及runloop實現機制以及類的+load方法執行時機等等方面的文章。
當我們希望走更遠時就會發現有一座大山阻擋著我們的去路。因為系統的閉源特性使得我們無法閱讀到其中所有的原始碼以及核心實現。那麼是否我們就只能裹足不前了呢?
回答是NO!
原始碼有高階形式的原始碼也有低階形式的原始碼。當我們被高階形式的原始碼所阻時,低階形式的原始碼卻依舊為我們敞開著大門,就看你願不願意去找那把鑰匙並開啟它。低階形式的原始碼是什麼呢? 答案就是機器指令!!
我們知道凡是滿足某個作業系統ABI規則的應用程式原始碼最終都會編譯和連結為某種特定格式的一條條機器指令並在CPU上執行。如果說程式的高階語言實現對於一個程式設計師來說是它的原始碼的話,那麼對於CPU來說一個程式的機器指令序列就是它的原始碼。只不過機器語言對於很多人來說異常的晦澀難懂而已。
很高興的一件事情就是雖然機器語言晦澀,我們的前輩們發明出了一種所謂機器語言的助記語言:組合語言
組合語言中的每條命令雖然幾乎和每條機器指令一一對應,但是卻增強了程式的可讀性,使得我們面臨的不再是一串乾巴巴的二進位制數字了。君不見目前很多的反編譯工具以及即使是XCODE上我們都能看到組合語言的場景。正是因為組合語言的出現使得我們在閱讀和分析原始碼上就進了一大步!
當你精通匯編語言時!你看到的所有程式碼都將是原始碼!
有人說組合語言相對於高階語言來說依然晦澀難懂,但這其實並不是絕對的。曾記得中國第一代程式設計師的求伯君以及雷軍這些前輩們最早接觸的就是組合語言,而且他們也都是用匯編語言進行程式編寫的。就因為組合語言離機器語言太近了,所以大家都會有一種望而生畏的感覺。誠然這些低階語言並沒有像我們使用的高階語言那樣更加符合自然語義和語法規則,但是它的優點就是非常的直接和單純。當你深入的應用它時就會發現彙編其實並沒有那麼的複雜。在一個程式的機器指令中,大部分的指令程式碼所做的事情除了計算外就是將資料在暫存器與暫存器之間以及暫存器與記憶體之間進行移動。在高階語言中我們可以定義非常個性化的變數以及無限制的變數,而在低階語言中我們則只能使用那幾個有限的暫存器來作為臨時變數,以及像訪問陣列那樣去訪問記憶體地址。
下面的一張圖可以看到實現一個累加功能程式碼片段的機器語言和組合語言以及高階語言之間的差別:
看上面的程式碼時也許你對高階語言所表達的意義一目瞭然,而對於組合語言的表達也許仔細多讀幾遍就能瞭解其意義,而對於機器語言則可能是一頭霧水了。
說了這麼多,也許有人會問組合語言和我想要深入iOS系統底層有什麼關係!
好問題! 答案就是iOS系統的封閉性,使得我們無法窺探到很多系統的底層實現, 並且當我們被某種問題或者某個實現原理所困擾卻不得其法時,就可以通過對系統進行反編譯而得到組合語言來了解和閱讀其實現原理;當我們面臨突如其來的執行時崩潰時,就可以通過閱讀組合語言來了解其產生的原因;當我們的crash並沒有上下文時,就可以通過組合語言來定位和解決問題;當我們想解決某個問題而想做動態下發補丁時我們也可以藉助組合語言來完成;當我們想在越獄的機器上hook住某些應用時我們可以通過組合語言來完成功能;當我們想最大的優化我們的系統以及某些關鍵部分的程式碼的效能時我們可以藉助組合語言;當我們想當一個黑客時我們可以藉助組合語言…,我們能借助組合語言做的事情實在是太多太多了。 現在的應用程式語言都是越來越向高階語言發展,而呈現出簡單化、智慧化從而導致進入的門檻越來越低。越高階的語言因為其封裝性就越離底層實現原理越遠,你所能窺探的東西就越少,因此低階語言還是非常具有頑強的生命力和存在必要性的。君不見iOS所開源的runtime的原始碼裡面關於objc_msgSend函式的實現就是用匯編語言來編寫的!這樣的目的就是讓這個函式的效能得到最大的優化。
所以說掌握和了解組合語言知識不僅是進入iOS系統底層並且也是進入所有系統底層的一把鑰匙,當你精通或者瞭解一些基礎的組合語言知識和技巧時,你就開啟了通往一切都是原始碼的大門。值得一提的就是我並不打算詳細的去介紹關於彙編的一切,其實我們只要瞭解一些基礎的彙編知識就能非常方便的幫助我們解決很多的事情。
敬請期待下一篇:深入iOS系統底層之指令集介紹
作者按
一直想寫一些關於系統底層方面的知識點,並且醞釀了很久。後來也跟其他人交流,你為何不出一個系列呢? 不必要一次性把所有的東西都寫完後才發表。我聽說後覺得非常的有道理,因此我想在這裡分享一些介紹iOS系統底層的一系列文章。這是第一篇開頭的引子,雖然自己的水平也很一般,但是想想自己還是有一些積累的,即使是有問題或者是有錯誤也可以發表出來供大家評論和指責嗎。最終的目的是大家共同進步,只要達到了這一點我也就滿足了。後續的日子我將會爭取每週在這個系列中對iOS系統底層進行一系列的展開,先列出一個大概的綱要,當然也許後續會有變化:
目錄
- 深入iOS系統底層之組合語言
- 深入iOS系統底層之指令集介紹
- 深入iOS系統底層之XCODE對彙編的支援介紹
- 深入iOS系統底層之CPU暫存器介紹
- 深入iOS系統底層之機器指令介紹
- 深入iOS系統底層之賦值指令介紹
- 深入iOS系統底層之函式呼叫介紹
- 深入iOS系統底層之其他常用指令介紹
- 深入iOS系統底層之函式棧介紹
- 深入iOS系統底層之函式棧(二)介紹
- 深入iOS系統底層之不定引數函式實現原理介紹
- 深入iOS系統底層之在高階語言中嵌入組合語言介紹
- 深入iOS系統底層之常見的彙編程式碼片段介紹
- 深入iOS系統底層之OC中的各種屬性以及修飾的實現介紹
- 深入iOS系統底層之ABI介紹
- 深入iOS系統底層之編譯連結過程介紹
- 深入iOS系統底層之可執行檔案結構介紹
- 深入iOS系統底層之MACH-O檔案格式介紹
- 深入iOS系統底層之映像檔案操作API介紹
- 深入iOS系統底層之知名load command結構介紹
- 深入iOS系統底層之程式載入過程介紹
- 深入iOS系統底層之靜態庫介紹
- 深入iOS系統底層之動態庫介紹
- 深入iOS系統底層之framework介紹
- 深入iOS系統底層之基地址介紹
- 深入iOS系統底層之模組內函式呼叫介紹
- 深入iOS系統底層之模組間函式呼叫介紹
- 深入iOS系統底層之機器指令動態構造介紹
- 深入iOS系統底層之crash問題解決方法
- 深入iOS系統底層之無上下文crash解決方法
- 深入iOS系統底層之常用工具和命令的實現原理介紹
- 深入iOS系統底層之真實的OC類記憶體結構介紹