深入iOS系統底層之指令集

不以規矩.不能成方圓。--《孟子·離婁上》

說到指令集以及CPU架構體系,大家就會想到計算機專業課程里面的計算機體系結構的方面的內容。既然課程中已經有了的內容我就不想那么枯燥的去復述一遍,而是先看一個類的定義:

//定義寄存器編號
typedef enum : int {
    Reg0,
    Reg1,
    Reg2,
    Reg3
} RegNum;


//定義系統調用編號
typedef enum : int {
    Int3         //設備輸出,將寄存器Reg0中的內容輸出到屏幕
} Interrupt;

//定義指令索引
typedef int Instruct;


/**
 虛擬CPU類,模擬CPU所提供的指令。
 虛擬CPU由4個寄存器和運算部件組成。四個寄存器的編號分別定義在RegNum中;運算部件提供了賦值、加減、比較、跳轉9個指令。
 */
@interface VCPU : NSObject

//將一個常量值賦值給編號為reg的寄存器中。
-(void)moveFromConst:(int)val toReg:(RegNum)reg;
//將編號為reg1的寄存器中的值賦值給編號為reg2的寄存器中。
-(void)moveFromReg:(RegNum)reg1 toReg:(RegNum)reg2;
//將編號為reg的寄存器中的值賦值給地址為addr的內存中。
-(void)moveFromReg:(RegNum)reg toAddr:(Addr)addr;
//將地址為addr的內存中的值賦值給編號為reg的寄存器中。
-(void)moveFromAddr:(Addr)addr toReg:(RegNum)reg;

//將編號為reg1的寄存器中的值加上編號為reg2的寄存器中的值并將結果保存到編號為reg2的寄存器中。
-(void)addFromReg:(RegNum)reg1 toReg:(RegNum)reg2;
//將編號為reg1的寄存器中的值減去編號為reg2的寄存器中的值并將結果保存到編號為reg2的寄存器中。
-(void)subFromReg:(RegNum)reg1 toReg:(RegNum)reg2;

//如果兩個寄存器內容相等則執行instruct所指定的指令,否則什么也不做。
-(void)isEqualReg:(RegNum)reg1 withReg:(RegNum)reg2 thenGoto:(Instruct)instruct;

//跳轉到instruct所指定的指令中去。
-(void)jumpTo:(Instruct)instruct;

//系統返回
-(void)ret;

//系統調用,目前只支持屏幕輸出調用Int3,表示將寄存器編號為0中的值輸出到屏幕。
-(void)sys:(Interrupt)interrupt;

@end


上面是一個叫VCPU的類的定義部分,它是一個用OC語言實現的用來模擬CPU功能的類。我們再來看一個使用這個類的代碼片段:


-(void)main:(VCPU*)cpu memory:(VMemory*)memory
{
    VINSTRUCT_BEGIN
    
    VINSTRUCT(0, [cpu moveFromConst:10 toReg:Reg0])             //將常數10保存到CPU的寄存器Reg0中
    VINSTRUCT(1, [cpu moveFromConst:15 toReg:Reg1])             //將常數15保存到CPU的寄存器Reg1中
    VINSTRUCT(2, [cpu addFromReg:Reg0 toReg:Reg1])              //將寄存器Reg0中的值于寄存器Reg1中的值相加并保存到Reg1中
    VINSTRUCT(3, [cpu moveFromReg:Reg1 toAddr:0x1000])           //將保存在Reg1中的相加結果保存到內存地址為0x1000處的內存中
    VINSTRUCT(4, [cpu moveFromAddr:0x1000 toReg:Reg0])           //將內存地址0x1000處的內存值保存到寄存器Reg0中
    VINSTRUCT(5, [cpu moveFromConst:25 toReg:Reg1])             //將常數25保存到CPU的寄存器Reg1中
    VINSTRUCT(6, [cpu isEqualReg:Reg0 withReg:Reg1 thenGoto:9]) //如果Reg0中的值和Reg1中的值相等則執行第9條指令:進行打印輸出
    VINSTRUCT(7, [cpu moveFromReg:Reg1 toAddr:0x1000])           //將寄存器Reg1中的值保存到內存地址為0x1000中。
    VINSTRUCT(8, [cpu jumpTo:10])                               //跳轉去執行第10條指令
    VINSTRUCT(9, [cpu sys:Int3])                                //系統調用,輸出保存在Reg0中的值。
    VINSTRUCT(10, [cpu ret])                                    //程序結束。
    
    VINSTRUCT_END

}

您能看懂上面代碼所實現的功能嗎(要想查看并運行完整的代碼請到我的 github站點中的VirtualSystem處下載)?您是否在例子里面隱約的感受到了上面代碼里面涉及到的一些關于CPU、內存、進程等方面的概念和知識了?它其實就是實現了如下的簡單功能:

    -(void)main
    {
         int  a = 10;
         int  b = 15;
         a = a + b;
         if ( a == 25){
               NSLog(@"output:%d",a);
           }
     }    

考察一下VCPU類,你會發現這個類提供了一些非常基礎的操作方法:加減處理、數據移動、比較、地址跳轉、系統調用等功能。調用者可以利用這個類提供的操作方法來編寫并完成某個特定的功能。這個類的內部實現還提供了幾個臨時存儲空間,可以通過RegNum編號來讀寫里面的數值。 VCPU實際上是一個對真實CPU所具有的能力的一個簡單的模擬類。我們來看一下CPU的組成:

CPU組成

從上面的CPU結構圖片中可以看出CPU主要分為存儲單元(SU)運算單元(ALU)以及控制單元(CU)。如果將這些部件和結構映射到VCPU這個類時你會發現:存儲單元所對應的就是里面的數據成員;而運算單元和控制單元則對應里面的所有實例方法,運算單元提供了CPU指令的實現(VCPU類提供了眾多的方法實現)。

我們稱一個CPU里面所提供的所有的指令的集合稱之為指令集。

我們可以用OC語言來實現一個VCPU類,也可以用Swift語言來實現一個Swift版本的VCPU類,也可以用Java語言來實現一個Java版本的VCPU類。 這其中不同的語言所提供的方法的定義形式是完全不同的: 就比如說OC里面可以提供直接操作內存地址的方法,但是Java里面則無法提供直接操作內存地址的方法;即使是OC語言中我們要實現VCPU類中的方法也可以有很多種不同的方式。

不同的廠家以及不同的技術工藝和技術水平以及具體的設備上所實現的CPU的體系架構以及提供的功能也是有差異的。比如ARM指令架構體系的CPU、x86指令體系架構的CPU、POWER-PC指令架構體系的CPU。這些不同體系的CPU因為架構完全不同導致所提供的指令和存儲單元也完全不同。我們不可能讓ARM指令直接在X86的CPU上執行(就如OC的提供方法無法在Java中執行是一個道理)。相同體系架構下的CPU指令則在一定程度上是可以相互兼容的,因為相同架構體系下的CPU的指令集是一致的(類比為接口一致,但是內部實現則不相同),比如說Intel公司所生產的x86系列的CPU和AMD公司所生產的x86系列CPU所提供的指令集是相似和兼容的,他們之間的差別只是內部的實現不同而已。

CPU指令集定義的是一個中央處理器所應該提供的基礎功能的集合,它是一個標準是一個接口也是一個協議。在軟件開發中具有協議和接口定義的概念,無論是消費者還是提供者都需要遵循這個標準來進行編程和交互:提供者要實現接口所具有的功能,至于如何實現則是內部的事情,不對外暴露,消費者也不需要知道具體的實現細節;消費者則總是要按接口提供的功能方法并組合使用來完成某種功能。這種設計的思維對于硬件系統也是一樣適用的。一般情況下某種CPU指令集通常都是由某些設計或者生產CPU的公司或者某標準組織共同定義而形成。那么目前市面上有哪些主流的CPU指令集或CPU架構體系呢?

  • x86/x64指令集

此處參考自:https://baike.baidu.com/item/Intel%20x86/1012845?fromtitle=x86&fromid=6150538

x86架構是Intel公司在1978年推出的Intel 8086中央處理器中首度出現,從Intel80386開始支持32位的系統。x86現在幾乎是個人計算機的標準平臺,成為了歷來最成功的CPU架構。其他公司也有制造x86架構的處理器:有AMD、Cyrix、NEC、IBM、IDT以及Transmeta等。

64位架構

到2002年,由于32位特性的長度,x86的架構開始到達某些設計的極限。這個導致要處理大量的信息儲存大于4GB會有困難。Intel原本已經決定在64位的時代完全地舍棄x86兼容性,推出新的架構稱為IA-64技術作為他的Itanium處理器產品線的基礎。IA-64與x86的軟件天生不兼容;它使用各種模擬形式來運行x86的軟件,不過,以模擬方式來運行的效率十分低下,并且會影響其他程序的運行。AMD公司則主動把32位x86(或稱為IA-32)擴充為64位。它以一個稱為AMD64的架構出現(在重命名前也稱為x86-64),且以這個技術為基礎的第一個產品是單內核的Opteron和Athlon 64處理器家族。由于AMD的64位處理器產品線首先進入市場,且微軟也不愿意為Intel和AMD開發兩套不同的64位操作系統,Intel也被迫采納AMD64指令集且增加某些新的擴充到他們自己的產品,命名為EM64T架構(顯然他們不想承認這些指令集是來自它的主要對手),EM64T后來被Intel正式更名為Intel 64(也就是x64指令集)。

在iOS編程時如果要運行在模擬器上,代碼生成的機器指令時就需要指定使用i386還是x64指令集,因為目前的mac電腦上基本采用了x86或者x64架構的CPU。

  • ARM指令集

此處參考自:https://baike.baidu.com/item/ARM/7518299

ARM處理器是英國Acorn有限公司設計的低功耗成本的第一款RISC微處理器。全稱為Advanced RISC Machine。ARM處理器本身是32位設計,但也配備16位指令集。1978年12月5日,物理學家赫爾曼·豪澤(Hermann Hauser)和工程師Chris Curry,在英國劍橋創辦了CPU公司(Cambridge Processing Unit),主要業務是為當地市場供應電子設備。1979年,CPU公司改名為Acorn公司。

起初,Acorn公司打算使用摩托羅拉公司的16位芯片,但是發現這種芯片太慢也太貴。"一臺售價500英鎊的機器,不可能使用價格100英鎊的CPU!"他們轉而向Intel公司索要80286芯片的設計資料,但是遭到拒絕,于是被迫自行研發。

1985年,Roger Wilson和Steve Furber設計了他們自己的第一代32位、6M Hz的處理器,

并用它做出了一臺RISC指令集的計算機,簡稱ARM(Acorn RISC Machine)。這就是ARM這個名字的由來。

目前市面上的主流智能手機等移動設備配備的CPU都采用ARM架構。iOS應用真機編譯出來的機器指令都是ARM指令,因此需要在編譯時指定armv7或者arm64指令集。

  • MIPS架構

此處參考自: https://baike.baidu.com/item/MIPS架構/1539401?fr=aladdin

MIPS架構(英語:MIPS architecture,為Microprocessor without interlocked piped stages architecture的縮寫),是一種采取精簡指令集(RISC)的處理器架構,1981年出現,由MIPS科技公司開發并授權,廣泛被使用在許多電子產品、網絡設備、個人娛樂裝置與商業裝置上。最早的MIPS架構是32位,最新的版本已經變成64位。

目前國內的龍芯CPU,采用的就是MIPS指令集。

  • POWER -PC

此處參考自:https://baike.baidu.com/item/POWER%20PC/5963071?fr=aladdin

POWER-PC由摩托羅拉公司和蘋果公司聯合開發的高性能32位和64位RISC微處理器系列,以與壟斷PC機市場的Intel微處理器和微軟公司的軟件相競爭。PowerPC微處理器1994年推出。

IBM以前跟Intel競爭過桌面處理器市場,但由于市場策略不當等原因,IBM沒賺到什么錢,于是決定退出桌面市場。POWER系列處理器是它退出桌面市場后才開發出來的服務器用處理器,蘋果電腦用的處理器只是Power系列里的一種,據說是IBM為蘋果特制的簡化版本,而蘋果獨一無二的經營理念使蘋果電腦與其它PC都不兼容,所以目前的Power系列處理器不能用于桌面PC。目前蘋果電腦因PowerPC處理器不適合蘋果發展而轉而使用Intel處理器。

您是否在很多iOS庫的頭文件里面看到過POWER-PC的宏定義,早期的蘋果電腦都用POWER-PC的CPU,現在蘋果電腦基本都改為x64架構的CPU了。

CPU體系的分類

上面列出了一些關于CPU架構和指令集的介紹,不同的體系結構具有各自的優缺點,我們可以從不同的角度對CPU進行分類:

按字長

所謂字長就是指CPU的指令在一個周期內能夠處理的最大的數字或者理解為對內存地址的最大的尋址能力。因此按這個長度可以做如下分類:

  • 8位(比如:Intel8086/以及一些小型家電的芯片)
  • 16位(比如:Intel80286)
  • 32位(比如:Intel的x86系列, ARM的armv7,armv7s系列)
  • 64位(比如:Intel的x64, ARM的arm64)

一般情況下大字長的CPU指令集都會兼容小字長的CPU指令集。比如32位的應用程序能夠在64位的CPU上執行,而小字長的CPU指令集則無法直接提供大字長指令集的能力,如需要支撐則通常都是通過模擬來完成的,比如說一個64位字長CPU的讀取數據指令在32位字長CPU上就可以通過模擬兩次讀取來完成,現在有的CPU提供了指令模擬的功能,因此某些64位的應用程序還是可以運行在32位的CPU上的,只不過性能和速度會存在很大的損耗。

按指令復雜度

此處參考自:https://wenku.baidu.com/view/b5a138d43186bceb19e8bb62.htmlhttps://zhidao.baidu.com/question/200786121943026445.html

所謂指令的復雜度就是指CPU指令集中所提供的指令的數量、指令尋址模式、指令參數、以及CPU內部的架構設計的復雜度、以及指令本身所占據的字節數等來進行劃分的一種方式,一般有兩種類型的分類:

  • CISC指令集。CISC的英文全稱為“Complex Instruction Set Computer”,即“復雜指令系統計算機”,從計算機誕生以來,人們一直沿用CISC指令集方式。早期的桌面軟件是按CISC設計的,并一直沿續到現在。目前,桌面計算機流行的x86體系結構即使用CISC。在CISC微處理器中,程序的各條指令是按順序串行執行的,每條指令中的各個操作也是按順序串行執行的。順序執行的優點是控制簡單,但計算機各部分的利用率不高,執行速度慢。CISC架構的服務器主要以x86/x64架構(Intel Architecture)為主,而且多數為中低檔服務器所采用。

  • RISC指令集。RISC的英文全稱為“Reduced Instruction Set Computer”,即“精簡指令集計算機”,是一種執行較少類型計算機指令的微處理器,起源于80年代的MIPS主機(即RISC機),RISC機中采用的微處理器統稱RISC處理器。這樣一來,它能夠以更快的速度執行操作(每秒執行更多百萬條指令,即MIPS)。目前的智能移動設備中的CPU幾乎都采用RISC指令集,比較有代表的就是ARM指令集和POWER-PC指令集。

下面的表格舉出了CISC和RISC兩種體系結構的差別:

RISC和CISC的差異比較
按指令流和數據流來

此處參考自:http://blog.csdn.net/conowen/article/details/7256260

按指令流和數據流來進行分類的依據是CPU的一條指令可以同時處理多少條數據,或者一條數據同時被多少條指令處理,以及在一個CPU時間周期內可以同時執行多少條指令等規則來劃分的。因此可以劃分為如下四種:

  • 單指令流單數據流機器(SISD)
    SISD機器是一種傳統的串行計算機,它的硬件不支持任何形式的并行計算,所有的指令都是串行執行。并且在某個時鐘周期內,CPU只能處理一個數據流。因此這種機器被稱作單指令流單數據流機器。早期的計算機都是SISD機器,如馮諾.依曼架構,如IBM PC機,早期的巨型機和許多8位的家用機等。

  • 單指令流多數據流機器(SIMD)
    SIMD是采用一個指令流處理多個數據流。這類機器在數字信號處理、圖像處理、以及多媒體信息處理等領域非常有效。Intel處理器實現的MMXTM、SSE(Streaming SIMD Extensions)、SSE2及SSE3擴展指令集,都能在單個時鐘周期內處理多個數據單元。也就是說我們現在用的單核計算機基本上都屬于SIMD機器。(個人覺得GPU也屬于這個范疇)

  • 多指令流單數據流機器(MISD)
    MISD是采用多個指令流來處理單個數據流。由于實際情況中,采用多指令流處理多數據流才是更有效的方法,因此MISD只是作為理論模型出現,沒有投入到實際應用之中。

  • 多指令流多數據流機器(MIMD)
    MIMD機器可以同時執行多個指令流,這些指令流分別對不同數據流進行操作。最新的多核計算平臺就屬于MIMD的范疇,例如Intel和AMD的雙核處理器等都屬于MIMD。

虛擬環境

最后我們還是回到VCPU類來,VCPU是一個對CPU的簡單的模擬實現。我們知道用vmware軟件可以用來模擬出一個操作系統運行的硬件環境,而實現了虛擬設備的功能;微軟公司在2017年宣布他的Visual studio 2017上能夠開發并運行iOS應用,并且可以無縫的將代碼拷貝到XCODE上編譯并運行。其實現的原理是Visual studio2017本身提供了一個OC語言編譯器,同時他內部也提供了一個Cocoa UI框架的模擬實現版本,所以能在上面運行iOS應用。

從上面的幾個例子中我們可以發現一個特點就是:一個系統各個層次之間的調用總是通過某些約定的規則或者定義的接口來進行的,并且調用者是不知道也不需要知道提供者是如何實現這些能力的,總是一切皆是接口:

接口的形式提供層次之間的調用

正是因為有這些接口的定義以及標準的形成,我們才可以將原本真實的實現模擬出另外一個虛擬的實現出來。這也就是所謂的虛擬化的本質。虛擬化可以發生在任何一個層面,也可以進行全局虛擬或者是部分虛擬。我們可以對CPU的指令以及硬件接口進行模擬從而構建出一套類似vmware一樣的虛擬機軟件來運行任何操作系統;我們也可以對操作系統提供的接口API進行模擬從而構建出一套類似Wine一樣的虛擬Windows運行環境出來;我們還可以對操作系統所提供的文件系統或者存儲系統來進行模擬從而提供出一套類似Docker之類的應用容器出來;我們也可以對Cocoa Framework進行模擬從而提供出一個套類似Vistual studio2017上能運行和編寫OC應用的編譯環境來(微軟開源了這個框架:微軟的OC實現支持)。

虛擬的實現原理

虛擬化首先要先接口標準定義,然后再在別人接口之上完成了一套自己的實現。現在的系統從上層的軟件到下層的硬件之間都是通過接口協議進行調用的,因此我們可以在各個層次上都實現虛擬的能力。

??【返回目錄


歡迎大家訪問我的github地址簡書地址

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