1. 程式人生 > 其它 >Arm入門第三講 Arm指令集學習 未完待續

Arm入門第三講 Arm指令集學習 未完待續

目錄

Arm入門第三講 Arm指令集學習

一丶Arm指令集

1.1 Arm指令集特點

  • 1.所有指令都是定長的: 4個位元組以內 x86指令是變長的可以很長很長.

  • 2.大部分指令都可以在一個時鐘週期內完成.這比x86好多了 x86為了優化指令週期才會進行程式碼優化

  • 3.每一條指令都可以有條件執行. (ADD, ADDEQ QNLY IF Z=1)

    這個條件執行大概是什麼意思那. 意思就是ADD是進行加運算,這與x86一樣. 但是ADD後面可以加條件狀態比如EQ. 如果加了EQ那麼他會先檢查狀態標誌位中的Z位. 從而決定執不執行這條指令 這個是ARM彙編的特點

  • 4.指令在通電之後可以配置為低位優先還是高位優先

  • 5.LOAD/STORE 模型,專有指令才能訪問記憶體 這一點是ARM特點. x86基本大部門指令都可以直接訪問記憶體.ARM只能用這個.

1.2 流水線執行

	流水線這個是CPU一個很重要的名字. 大概是什麼意思那. 意思就是 把一條指令分成多個階段分別指令.

以x86彙編為例子

mov eax,10
add eax,11
mov ebx,12
add ebx,13

可以看到 指令是從上往下執行的. 第二條指令需要依賴於第一條指令的結果. 這樣就會導致效率很慢.

但是觀看指令我們就可以優化為下面的指令

mov eax,10
mov ebx,11
add eax,11
add ebx,12

這樣 第二條彙編就不依賴與第一條彙編指令了. 這就算是簡單的優化了. 而流水線不只是這些. 那麼下面就說下需要了解的名次把.

  • Arm 使用的是三級流水線. 來加快指令的處理速度.

    ​ 流水線技術可以使得多個操作同步進行 記住是同步進行. 而不是序列進行. 試想一下,如果我們的第二條彙編依賴於第一條彙編的結果.那麼是不是就必須等待第一條彙編執行完畢才能執行. 如果是這樣就不可以同步執行了.

    Arm三級流水線 分別是 取址(fetch) 譯碼(decode) 執行(execute) 而在ARM彙編中.它的R15暫存器 也就是PC暫存器 執向的就是 fetch指令

  • x86則使用五級流水線

    分別就是 取址(fetch) 譯碼(decode) 轉址(translate)執行(execute)寫回(wb)

二丶Arm指令格式(重要)

2.1 Arm Opcode

​ 在x86下指令格式有x86形式. Arm同樣也有自己的指令格式. 知道指令格式可以編寫反彙編偵錯程式等.

當然如果不寫的話那麼學習Arm也要了解指令格式.

首先在32位下有如下圖:

總共 32位. 其中這裡介紹下什麼意思

Condition : 是用來存放我們條件碼的. 比如AddEQ 後面的EQ就是條件 NE等...

I 他不會在指令之中,他表示第二運算元的型別標誌碼, 因為我們無法確定第二操作樹的型別

Opcode 位於第21-24位之間(4位) 是用來存放我們的操作碼 比如他們的助記符 Add Mov

S =1 表示是否影響我們的CPSR暫存器. 也就是比如MOVS 那麼就會影響

Rn 表示第一源暫存器,表示是要從這個暫存器中取資料給RD的 ADDS R0,R1,R2 那麼R1就是這裡表示的,第一運算元的意思

Rd 表示目的暫存器,是用來存放我們的結果的

Operand2 表示第二操作樹的,RN表示第一運算元,他可以有多種形式,可以是立即數 可以是暫存器. 也可以是暫存器加移位,如: MOVS R3,R1 LSL #2

特殊:

BL W W不在指令中.這個只是指令寬度的說明符. 不會影響指令的行為 比如單獨寫 bl 那麼又可能是16位的,也可能32位. 
而我們Keill反彙編的時候 BLW則表示32位. 單獨的bl則是16位

Operand2 疑問:

第二運算元,大小是0-11位表示. 如果是0-11位表示那麼他如何能表示一個32位的數那? 是不是就不行了那?

2.2 指令組成格式瞭解

指令組成格式看下圖:

上面說了指令格式中的意思. 那麼這個就是指令格式組成了.

其中在這個圖中有很多 <> {} 那麼分別說下什麼意思把

<> 代表這一項是必須要有的. 而不是能省略的.

{} 代表是可選的就是說可以不要的.

比如有個指令為:

ADDS  那麼ADD 就是Opcode 是必須要的  S代表是修改CPSR狀態的. 那麼中間就把條件給省略了.
你也許看到過 ADDEQ 那麼EQ就是帶有條件的.

2.3 I模式詳解

如果 I 模式為立即數方式

如果為立即數方式,那麼看下圖

如果為立即數方式,那麼我們的第二操作樹就按照上面進行解析. 拆分為 4 8組合.

也就是一個32位的數可以用這個12位進行表示. 但是這個32位數必須是由一個八位的常數,迴圈右移偶數位得到的.

其中迴圈右移的位數是由一個四位的二進位制數的兩倍來進行表示的.

比如說我們有一個立即數為

4096  那麼我們的八位數最高能表示0xFF(255)位元組大小

2.4 指令的條件執行

有以下指令

ADD R0,R1,R2          這個就代表無條件執行 R0 = R1 + R2
ADDEQ R0,R1,R2        這個就代表有條件的執行 if (zF == 1){R0 = R1 + R2} ZF = 1表示兩數相等 ZF = 0 表示NE不想等  EQ是相等的意思
ADDS R0,R1,R2		 這裡字尾帶S 不會不是判斷條件執行而是設定. R0 = R1 + R2 然後SET CPSR 中的ZFlag位

好處:

​ 指令更加精簡了. 看如下程式碼(不懂沒關係)

CMP R3,#0 比較R3與立即數0
BEQ  Skip 如果相等則跳轉到skip標籤執行
ADD  R0,R1,R2  這裡就是如果不想等則會執行 R0 = R1 + R2
Skip:     這是標籤

第二個程式

CMP R3,#0  同上
ADDNE R0,R1,R2  在ADD同時帶上條件.  如果不想等 R0 = R1 + R2

所以觀看兩種彙編程式碼.發現第二種更簡潔.且更好看.

ARM指令後面都可以跟上條件碼,下面就是收集的條件碼

三丶Arm彙編指令學習

3.1 Arm的加減彙編指令

Arm的加減彙編指令分為如下:

ADD 加法指令
ADC 帶進位加法指令
SUB 減法指令
SBC 帶借位的減法指令
RSB 逆向減法指令
RSC 帶借位的逆向減法指令
  • ADD加法指令

    ADD 指令,是用於把兩個運算元相加,並且將結果放到目的暫存器中.

    運算元1(op1)應是一個暫存器,運算元2可以是一個暫存器,也可以是一個立即數,也可以是一個移位暫存器.

    ADD{條件}{S}<dest>,<op1>,<op2>
    例子:
    ADD R0,R1,R2   將R1 + R2賦值給R0 也就是 R0 = R1 + R2
    ADD R0,R1,#2   暫存器與立即數之間的加法操作 R0 = R1 + 2
    ADD R0,R2,R1,LSL@1 包含移位運算的加法操作,先進性移位操作.在進行加法操作
    R0 = R2 + (R1 << 1)
    

    指令中如果帶有S字尾 那麼就是要影響 ARM中的狀態暫存器 狀態暫存器 CPSR 也是一個32位 的暫存器. 主要就是儲存程式的執行狀態. 比如 第29位C標誌 那麼 如果 R0 = R1 + R2(目的暫存器 = 運算元1 + 運算元2) 兩個32位數相加的結果超出了32位 就會產生進位 那麼 C標誌就會設定為1 否則C就設定為0 如果ADD指令中不加 S字尾的話.那麼兩數相加 結果是否產生進位都不會改變 CPSR暫存器

    MOV R1,#0XF1000000
    MOV R2,0X800000000
    ADD R0,R1,R2   可以檢視CPSR中的C位是否發生改變
    ADDS R0,R1,R2  可以檢視CPSR中的C位是否發生了變化
    

    溢位位的瞭解

    C標誌位 如果在加法運算中 產生了進位. 那麼C = 1 這表示無符號運算髮生了上溢位了. 其它情況則為0

    C標誌位 如果在減法運算中產生了借位. 那麼C = 0. 簡單理解就是C儲存了進位.減法借位之後就沒了.

    這有個名詞,意思就是表示無符號運算髮生了下溢位. 其它情況下C為1. 正好與加法相反

  • SUB 減法指令

    SUB指令用於把運算元1減去運算元2的結果 放到目的暫存器中. 運算元1 可以是暫存器. 運算元2 可以是

    立即數 移位暫存器 (與ADD一樣)

    例子:

    SUB{條件}{S}<dest>,<op1>,<op2>
    SUB R0,R1,R2    R0 = R1 - R2
    SUB R0,R1,#256  R0 = R1 - 256
    SUB R2,R1,R3,LSL#1   R2 = R1 -(R3<<1)