深刻iOS系統底層之指令集

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

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

//定義寄存器編號
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功能的類。咱們再來看一個使用這個類的代碼片斷:github

-(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、內存、進程等方面的概念和知識了?它其實就是實現了以下的簡單功能:objective-c

-(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架構體系呢?post

  • x86/x64指令集

此處參考自:baike.baidu.com/item/Intel …

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指令集

此處參考自:baike.baidu.com/item/ARM/75…

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的處理器,

Roger Wilson和Steve Furber

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

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

  • MIPS架構

此處參考自: baike.baidu.com/item/MIPS架構…

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

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

  • POWER -PC

此處參考自:baike.baidu.com/item/POWER …

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上的,只不過性能和速度會存在很大的損耗。

按指令複雜度

此處參考自:wenku.baidu.com/view/b5a138…

所謂指令的複雜度就是指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的差別比較

  

按指令流和數據流來

此處參考自:blog.csdn.net/conowen/art…

按指令流和數據流來進行分類的依據是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地址

相關文章
相關標籤/搜索