雖然前段時間ARM被日本軟銀收購了,可是科技是無國界的,因此呢ARM相關知識該學的學。如今看ARM指令集仍是倍感親切的,畢竟大學裏開了ARM這門課,而且作了很多的實驗,當時自我感受ARM這門課學的仍是能夠的。雖然當時感受學這門課之後彷佛不怎麼用的上,可曾想這不就用上了嗎,不過以前學的都差很少忘了,還得撿起來呢。ARM指令集是精簡指令集,從名字咱們就能看出指令的個數比那些負責指令集要少一些。固然本篇所涉及的ARM指令集是冰山一角,不過也算是基礎,能夠閱讀Hopper中的彙編了,實踐出真知,看多了天然而然的就會了。編程
1、Hopper中的ARM指令數據結構
ARM處理器就很少說了,ARM處理器由於低功耗等緣由,因此大部分移動設備上用的基本上都是ARM架構的處理器。固然做爲移動設備的Android手機,iPhone也是用的ARM架構的處理器。若是你想對iOS系統以及你的應用進一步的瞭解,那麼對ARM指令集的瞭解是必不可少的,ARM指令集應該也算得上是iOS逆向工程的基礎了。架構
當你使用Hopper進行反編譯時,裏邊全是ARM的指令,那是看的一個爽呢。下面就是使用Hopper打開MobileNote.app的一個Hopper的界面。從主窗口中能夠看到全是ARM的指令呢,若是你對ARM指令不瞭解,那麼如何進行分析呢,對吧。因此對ARM指令的瞭解,是iOS逆向工程的基礎呢。今天這篇博客就總結一下ARM指令集的基礎指令。app
Hopper的功能是很是強大的,在Hopper中你能夠對ARM指令進行修改,而且生成一個新的可執行文件。固然Hopper強大的功能能夠幫助你更好的理解ARM彙編語言的業務邏輯,Hopper會根據ARM彙編生成相關的邏輯圖,以下所示。從下方的邏輯圖中你就能清楚的看到相關ARM彙編的指令邏輯。紅線代表條件不成立時的跳轉,藍線則代表條件成立時的跳轉。函數
Hopper的功能強大到能夠將ARM彙編生成相應的僞代碼,若是你看ARM指令不直觀的話,那麼僞代碼對你來講會更好一些。下方就是Hopper根據ARM指令生成的僞代碼,以下所示。測試
貌似有點跑偏了,今天的主題是ARM指令集,Hopper的東西就不作過多贅述了。ui
2、ARM指令集綜述spa
ARM指令主要是對寄存器,棧、內存的操做。寄存器位於CPU中,個數少速度快,ARM指令集中大部分指令都是對寄存器操做,但有些指令是對棧和內存的操做。下方會對操做棧、寄存器以及內存的指令進行介紹。blog
1.棧操做---- push 與popip
先簡單的聊一下棧的概念,「棧」說白了就是數據結構的一種,棧的數據結構具備LIFO(last in first out) ---- 後進先出的特色。棧在ARM中所指的實際上是一塊具備棧數據結構特色內存區。棧中主要用來暫存寄存器中的值得,好比R0寄存器正在使呢,但是如今有一個優先級比較高的函數要使用R0, 那麼就先把R0的值Push到棧中暫存,而後等R0被優先級更高的函數使用完畢後在從棧中Pop出以前的值。在函數調用時通常會對棧進行操做。
對棧操做的命令就是push和pop了,通常會成對出現,在函數開始時將該函數執行時要使用的寄存器中的值push入棧,而後在函數結束時將以前push到棧中的值在pop到相應的寄存器中。
下方就是push和pop的用法的一個實例。在下方函數開始執行前,將該函數要使用的寄存器r4, r5, r7, lr使用push進行入棧操做,lr是該函數執行後要返回的地址。在函數執行完畢後,使用pop命令將函數執行前入棧的值在pop到相應的寄存器中。有一點須要注意的是將lr寄存器中的值在函數結束後pop到pc (Program Counter)寄存器中,pc寄存器中存儲的是將要執行的命令的地址。這樣一來,函數執行後就會返回到以前執行的地址上繼續執行。
2. pc寄存器中的中的標誌位
此處咱們以32位指令爲例,pc寄存器中的後四位是標誌位,第28 - 31位分別對應着V (oVerflow),C (Carry),Z (Zero),N (Negative)。下面分別來介紹一下這四種符號所表示的狀態。
3. 命令操做符
下方是ARM指令集中經常使用的算術操做:
(1)加法操做
(2)減法操做
(3)、乘法指令
在ARM指令集中,乘法指令有兩種第一個是MUL, 第二個是帶累加的乘法MLA。固然,這兩個指令使用起來都不復雜。
(4)、邏輯操做
邏輯操做比較好理解一些,與咱們編程中使用的邏輯操做大同小異,無非是一些與、或、非、異或這些操做。
四、寄存器的裝載和存儲
有時咱們須要將內存中的數據裝載到寄存器中進行操做,或者將寄存器中運算後的數據存儲到內存中,此時咱們就會用到寄存器的裝載和存儲的相關命令。下方就一一的總結了這些命令。
(1)、傳送單一數據
LDR{條件} Rd, <地址> ;將地址中的數據加載到Rd寄存器中
STR{條件} Rd, <地址> ;將寄存器Rd中的數值存儲到<地址>中的內存中
LDR{條件}B Rd, <地址> ;將內存地址所對應值得低8位加載到Rd的寄存器中。
STR{條件}B Rd, <地址> ;將寄存器Rd的後8爲存的到內存地址中。
(2)、一次傳送兩個數據
(3)、塊數據存取
(4)、單一數據交換:SWP
SWP命令用來交換寄存器與內存直接的值,下方是SWP的指令格式:
SWP{條件}{B} Rd, Rm, [Rn]
上述命令表示將Rn中內存地址所指向內存中的數據加載到Rd中,而後將寄存器Rm中的值存儲到該內存地址指向的區域中。若是Rd = Rm, 那麼Rn指向的內存中的值就會與Rd進行交換。若是加上條件後綴的話,就說明在知足該條件時進行操做,後綴B則是操做低8位。
五、比較、分支與條件指令
分支與條件指令是編程中不可或缺的指令,在處理一些特定的業務邏輯時會常用到分支與條件指令。分支說白了就是跳轉,而分支與條件結合使用就是當知足必定條件後進行特定的跳轉。接下來,將總結一下ARM指令集中經常使用的分支指令與條件指令,更確切的說是條件後綴。
(1)、比較指令
在ARM指令集中使用到的比較指令有CMN、CMP、TEQ、TST。有一點須要注意的是CMN與CMP是算術指令,TEQ和TST屬於邏輯指令。比較指令在執行後老是會設置標誌位(N、Z、C、V), 由於條件後綴是根據被設置的標誌位來判斷比較結果是否知足條件的。下方會給出詳細的條件後綴。比較命令後方也是能夠添加條件後綴的。
(2)、分支指令
經常使用的分支指令是B、BL、BX這三個指令。
(3)、條件後綴
上述的分支指令與條件後綴結合才能發揮其強大的功能和做用,解析這部分介紹的是就是咱們的條件後綴。條件後綴不能單獨的使用,要和其餘命令一塊結合使用,而後根據條件的結果來作一些操做。下方是全部條件後綴,條件是否成立是根據NZCV這四個標誌位來判斷的,由於咱們在對一些數值進行比較時,會設置相應的標誌位。而後咱們就可使用這些標誌位來判斷條件是否成立。NZCV就是咱們以前所提到的幾個標誌位,Z(是否爲零), C(是否進位), N(是否爲負), V(是否溢出)四種標準位來判斷的。
6. 移位操做(LSL、ASL、LSR、ASR、ROR、RRX)
移位操做在ARM指令集中不做爲單獨的命令使用,它在指令格式中是一個字段。接下來將會介紹一下各類移位操做。若是你以前學過「數字電路」這門課的話,那麼你確定對這些移位操做並不陌生。
(1)、LSL ---- 邏輯左移(Logical Shift Left)與 ASL ---- 算術左移 (Arithmetic Shift Left)
邏輯左移與算術左移的操做是同樣的,都是將操做數向左移位,低位補零,移除的高位進行丟棄。接下來咱們來看一個示例,根據這個示例來看一下LSL或者ASL的工做方式。
MOV R0, #5
MOV R1, R0, LSL #2
上述命令,就是將5存儲到R0寄存器上(R0 = 5), 而後將R0邏輯左移2位後傳送到R1寄存器中。十進制5的二進制數值是0101,進行邏輯左移2位就是0001_0100, 也就是十進制中的20。其實沒邏輯左移1位就至關於原數值進行乘2操做,5邏輯左移2位其實就是5 x 2^2 = 20。下方是該操做的原理圖
(2)、LSR ---- 邏輯右移(Logical Shift Right)
邏輯右移與邏輯左移是相對的,邏輯右移其實就是往右移位,左邊補零。用法與LSL相似,在此就不作過多贅述了。
(3)、ASR ---- 算術右移(Arithmetic Shift Right)
ASR與LSR相似,惟一不一樣的是,LSR的高位補零,而ASR的高位補符號位。符號位爲1,那麼就補1,符號位爲0那麼就補零。
(4)、ROR ---- 循環右移(Rotate Right)
循環右移,見名知意,就是循環着往右移動,右邊移除的位往高位進行填補。
今天的博客就先到這吧,畢竟篇幅有限,上面的命令是一些基本命令。其餘的浮點指令在此就不作過多贅述了,如ABS--絕對值、ACS--反餘弦、ASN--反正弦等等,就留個讀者本身去看吧。