1. 程式人生 > >arm第九天(彙編之指令下)

arm第九天(彙編之指令下)

ARM七種工作模式

  • 管理
  • 快速中斷
  • 中斷
  • 中止
  • 未定義
  • 系統
  • 使用者

ARM執行狀態

  • ARM狀態 arm指令 32bit 地址字對齊(整除4),最後兩bit為0
  • Thumb狀態 thumb指令 16bit 半字對齊,最後1bit為0

ARM暫存器
不同的狀態,訪問不同的暫存器
R0-R12 共用
R13(SP) 儲存棧頂指標
R14(LR) 用來儲存返回地址 如,BL,在跳轉前要儲存下一條指令的地址
R15(PC) 用來儲存需要取指指令的地址
取指、解碼、執行
CPSR(1個)
模式位 bit[4:0]
執行狀態bit[5]
FIQ禁止位 bit[6]
IRQ禁止位 bit[7]
條件標誌位bit[31:28] NZCV
SPSR(5個)
ARM支援資料型別:位元組、字、半字
ARM記憶體對齊方式:字、半字、位元組

跳轉指令

  • B 可以用來構建迴圈執行
    相對跳轉 PC(new) = PC(當前) +/- 偏移(32MB) 無返回
  • BL 常用來呼叫子函式
    相對跳轉 PC(new) = PC(當前) +/- 偏移(32MB) 帶返回
    CPU會自動將下一條指令地址儲存到LR
    MOV PC,LR
  • BX
    絕對跳轉
    CPSR[5] = Rm[0]
    PC = Rm & 0xFFFFFFFE
  • BLX

資料處理指令

案例:

ADD R0,R1,#1 //R0 = R1+1
MOVEEQ R0R2 //條件執行,在EQ(相等)條件下,招行R0 = R2
SUBEQS R0,R1,R2,LSR
#1 // 在EQ條件下,R0 = R1-(R2>>1) CMP R1,R3 //R1-R3

資料處理指令可細分為4類:
資料傳送指令(MOV,MVN)
算術運算指令(ADD,ADC,SUB,SBC,RSB)
位運算指令(AND,ORR,EOR,BIC)
比較指令(CMP,CMN,TST,TEQ)
資料處理指令的一般格式:
{cond} {S} ,,
:指令操作碼,如ADD,MOV,SUB
{cond}:條件,如EQ
{S} :分兩種情況
1,當目標暫存器不是PC時,根據目標暫存器的結果影響CPSR的NACV條件標誌位

 MOVS R0,R2  //因為MOV
加了S,根據R0的結果影響NZCV

2,當目標暫存器是PC時,CPSR = SPSR,如:

 MOVS PC,LR  //PC=LR,CPSR = SPSR 異常的返回; 這種指令只能在異常模式下面使用

:目標暫存器
:第一源運算元,只能是暫存器
:第二源運算元
1,立即數:相當於常量,直接出現在指令中,不用儲存在暫存器或儲存器,如:

  ADD R0,R1,#3

2,暫存器,如

ADD R0,R1R2 //R0 = R1 + R2

3,暫存器移位,把暫存器裡面的值進行不到的移位操作得到的結果。
3.1 ,LSL #,如

ADD R0,R1,R2 LSL #1  //R0 = R1 + (R2 << 1) ,邏輯左移,空出低位用0填充

3.2 ,LSL ,如

ADD R0,R1,R2 R2 LSL R3  //邏輯左移,空出低位用1填充,左移的位數放在了R3暫存器中

3.3 ,LSR #,如

ADD R0,R1,R2 LSR #1  //R0 = R1 + (R2 >> 1) ,邏輯右移,空出的高位用0填充

3.4 ,LSR ,右移的位數放在了暫存器中
3.5 ,ASR #
這裡寫圖片描述
3.6 ,ASR
3.7 ,ROR #
這裡寫圖片描述
ROR迴圈右移:移出的低位用於填充空出的高位
3.8 ,ROR
3.9 RRX
這裡寫圖片描述
RRX:擴充套件右移一位,將Rm暫存器的內容右移一位,空出的高位用原來的CPSR的位填充,
並Rm移出的1位填充CPSR的C位,
只有RRX,不需要指定移位位數

第一源運算元:暫存器
第二源運算元(11種):
1,立即數
2,暫存器
3,暫存器移位
1, lSL #shift
2,LSL Rs 空出的低位用0填充
3,LSR #shift
4,LSR Rs 空出的高位用0填充
5,ASR #shift
6,ASR Rs 空出的高位用符號位填充
7,ROR #shift
8,ROR Rs 迴圈右移,將移出的低位填充空出的高位
9, RRX 擴充套件右移一位

立即數(8點陣圖立即數):
CMP R1,#0x4800000
32 bit 機器碼
這裡寫圖片描述

這裡寫圖片描述
找到8bit立即數,然後將8bit立即數擴充套件為32bit,再將32bit的數採用迴圈右移的方式進行移位,移2X(rot)次,最終得到0x04800000,將0x12擴充套件成32bit,高位全用0填充,然後將迴圈右移2*5 = 10 次
0x04800000
5 0x12 迴圈右移10次
6 0x48 迴圈右移12次
如果找到的組合不唯一,取迴圈次數少的那組。

合法立即資料的判定?
1,0-0xFF 就是立即數
MOV R1,0x55 //R1 = 0x55
2,立即數中1的個數大於8的一定不合法
3,從兩個方向看1的間距大於8,非法

資料傳送指令
指令格式
MOV{cond}{S} ,
shifter_operand:立即數(8點陣圖)、暫存器、暫存器移位
示例:

MOVEQ R0,#0x80 //在EQ的條件下,R0=0x80
MOVS PC,LR   //由於MOV後有S,PC = LR,CPSR= SPSR,用於異常返回;只能在異常模式下使用
MOVEQS R0,R1 //在EQ條件下,後面加有S,根據R0的結果去影響CPSR的NZCV,
             //後面幾行程式碼是具體影響方法
     N = R0[31] //符號位
     Z = if R0 == 0 then 1 else 0 //為正?為負?
     C = shifter_carry_out,
     不影響V,V代表溢位
MOV R3,R4,LSL #2  //R3 = (R4 << 2)
MOV R0,R0  //R0 = R0
MOV PC,R14  //PC = R14

NZCV:
N:運算結果為負值的標誌位
N= 1,負值
N= 0,正值
Z:運算結果為0的標誌位
Z=1,結果為0
Z= 0,結果為非0

資料反傳送指令:MVN
指令格式:
MVN{cond}{S} ,
功能:Rd = 按位取反
shifter_operand:立即數(8點陣圖),暫存器,暫存器移位
示例:

MOVNEQ R0,#0x80 //EQ,將0x80按位取反  R0 = 0xFFFFFF7F
MVNS PC,R0 //後面加了S,PC = R0按位取反,CPSR = SPSR ;異常返回
MVNEQS R0,R1 //EQ,R0 = R1按位取反,R0影響CPSR的NZCV
    N = Rd[31]
    Z = if Rd ==0 then 1 else 0
    C = shifter_carry_cout
    不影響V
MVN R3,R4,LSL #2 // R3=(R4<<2)

案例:

MOV R0#0x00 //R0 =0x00
MVN R0#0x00 //R0 =0xFFFF,FFFF
MOV R0,#0xffffff00  //非法立即數 
MVN R0,#0x000000FF //R0 = 0xffffff00

小結:
MOV
MVN
這兩指令沒有第一源運算元
S:
PC,CPSR= SPSR
不是PC,根據結果影響CPSR的NZCV

算術指令
加法指令:ADD
指令格式
ADD{cond}{S} ,,
功能:Rd = Rn +
示例 :

ADD R0,R1#0x80  //
ADDEQ R0,R1,R3
ADDS R0,R1,R2  //R0 = R1+R2根據R0結果影響NZVC
    N = Rd[31]
    Z = if Rd ==0 then 1 else 0
    C = CarryFrom(Rn+shifter_operand)
    V = OVerflowFrom(Rn+shifter_operand)
ADDS PC,R1,#0 //PC = R1,CPSR = SPSR

NZCV:
N:運算結果為負值的標誌位
N= 1,負值
N= 0,正值
Z:運算結果為0的標誌位
Z=1,結果為0
Z= 0,結果為非0
C:運算結果產生進位的標誌位
進位針對無符號數來說
C= 0 ,有進位
C = 1,無進位
V:運算結果產生溢位的標誌位
溢位針對有符號數來說
V= 0 ,有溢位
V = 1,無溢位

8bit
有符號:-128~127
無符號:0~255

3AH + 7CH = B6H //H表示十進位制
無符號:58+124 = 182,沒有超過255,無進位
有符號:58+124 = 182,超過了127,溢位

AAH + 7CH = B6H //H表示十進位制
無符號:170+124 = 294,沒有超過255,有進位
有符號:-86+124 = 38,沒有超過了127,無溢位

帶進位的加法:ADC
指令格式:
ADC{cond}{S} ,,
功能: Rd = Rn + + C位
示例 :

ADC R0,R1,#0x80 //R0 = R1+0x80+C
ADCEQ R0,R1,R3  //EQ,R0 = ..
ADCS R0,R1,R3 //R0 = Ra+R2+C,根據R0的值,影響CPSR的NZCV
    Z = if Rd ==0 then 1 else 0
    C = CarryFrom(Rn+shifter_operand + C Flag)
    V = OverflowFrom(Rn+shifter_operand + C Flag)
ADCS PC,R1,#0 //

案例:

加數(R1,R0)
被加數(R3,R2)
結果(R1,R0)
前者為高32位,後者為低32位

減法指令
指令格式:
SUB{cond}{S} ,,
示例:

SUB R0R1,#0x80 //R0 = R1-0x80
SUBNE R0,R1,R3 //NE,R0 = R1-R3
SUBS R0,R1,R2 //R0 = R1-R2,根據結果R0影響CPSR的NZCV
    Z = if Rd ==0 then 1 else 0
    C = NOT BorrowFrom(Rn-shifter_operand)
    //有借位 C= 0
    //無借位 C= 1
    V = OverflowFrom(Rn-shifter_operand )
SUBS PC,R14,#04 //PC = R14 - 4,CPSR = SPSR     異常返回

案例:

SUB R0,R1,R2
SUB R0,R1,#256
SUB R0,R2,R3,LSL #1 //R0 = R2 - (R3<<1);
SUBS R0,R1,R3  //R1 = R2-R3,影響NZCV
SUBS PC,R14,#4  //同上

帶借位的減法指令:SBC
指令格式:
SBC{S} ,,
功能: Rd= Rn- shifter_operand - Not C
示例:

SBC R0,R1,#0x80  //R0 = R1 - 0x80 - Not C
SBCNE  R0,R1,R3 //NE,R0 = R1 - R3 - Not C
SBCS R0,R1,R2//R0 = R1-R2,根據結果R0影響CPSR的NZCV
    Z = if Rd ==0 then 1 else 0
    C = NOT BorrowFrom(Rn-shifter_operand - NOT(C Flag))
    V = OverflowFrom(Rn-shifter_operand -  NOT(C Flag))
SBCS PC,R1#0

反向減法指令:RSB
指令格式:
RSB{S} ,,
功能:
Rd = - Rn
示例:

RSB R0,R1,0x80 // r0= 0x80-r2
RSBNE R0,R1,R3 //NE,R0= R3-R1
RSBS R0,R1,R2 //R0= R2-R1,影響NZCV
....
PSBS PC,R1,#0
RSB R3,R1,#0 //R3 = -R1;
RSBS R1,R2,R2,LSL #2 //R1=(R2<<2)-R2 = R2*3,用反向減法實現乘法
//會影響標誌位

帶借位的反向減法指令:RSC
指令格式:
RSC{S} ,,
功能:Rd= shifter_operand - Rn - Not C
示例:

RSC R0,R1,#0x80 //R0 = 0x80 - R1- Not C
RSCNE  R0,R1,R3  //R0 = R3 - R1- Not C
RSCS R0,R1,R3 //R0 = R3 - R1- Not C,由於加了S,會根據結果影響NZCV
N=Rd[31]
  Z = ...
  C = NOT BrowwFrom(shifter_operand - Rn - Not(C Flag))
  ...

總結
算術運算:
ADD 加法 Rd = Rn + C = 1 進位,C= 0無進位
ADC 帶進位的加法 Rd = Rn + +C 位
SUB 減法 Rd = Rn - , C = 0 有借位,C= 1無借位
SBC 帶借位的減法 Rd = Rn - - Not C
RSB 反向減法 Rd = - Rn
RSC帶借位的反向減法 Rd = - Rn - Not C
如果指令程式碼加了S:
1),目標PC,CPSR = SPSR 異常返回,只能在異常模式下進行
2),不是PC,根據Rd結果,影響CPSR的NZCV

位運算指令(與、或、異或、位清除)
位與指令:AND
指令格式:
AND{S} ,,
指令功能:
Rd = Rn &

AND R0,R1,0x80 //R0=R1&0x80,把R1的bit7保留,其餘清0
ANDNE R0,R1,R3//NE ,R0=R1&R3
ANDS R0,R1,R3  //R0=R1&R3,由於後面加了S,會根據R0的結果影響NZCV
    N = Rd[31]
    Z= if Rd == 0 ..
    C = shifter_carry_out
ANDS PC,R1,#0xFFFFFFFF
ANDS R0,R1,R2,LSL #1 //R0 = R1& (R2<<1)

按位操作實現什麼目的?
&1 用來判斷某位是1還是0
&0 清除某一位

位與指令:ORR
指令格式:
ORR{S} ,,
指令功能:
Rd = Rn |

ORR R0,R1,#0x80//將R1的bit[7]置1
ORRNE R0,R1,R3
ORRS R0,R1,R2
   N = Rd[31]
   Z = if Rd  == 0 then 1 else 0
   C = shifter_carry_out
OPRS PC,R1,#0x0 //異常返回
ORR  R0R1,R2,LSL #2

用或操作實現什麼?
|1 ,將某位置1
|0,保留某些位,保持不變

異或指令:EOR
指令格式:
EOR{S} ,,
指令功能:
Rd = Rn^
這裡寫圖片描述
示例

EOR R0,R1,#0x80
...

用異或操作實現什麼?
相同 為 0
不同 為1
1,判斷兩個數是否相等
EORS R3,R1,R2
R1^R2 == 0 表示 R1==R2
2,把一個變數的某位與1做異或可以實現取反
0 ^ 1 = 1
1^ 1 = 0
3,加密
0x80^ 0xFF = 1000,0000^ 1111,1111 = 0111,1111 = 0x7F
0x7F^ 0xFF = 0111,11111 = 1111,1111 = 1000,0000=0x80
這裡的0xFF就相當一個金鑰

EOR R0,R0#FF
EOR R0,R0,R1
EORS  R0,R0,#1

位清除指令:BIC
指令格式:
BIC{S} ,,
指令功能:
Rd = Rn&(~ )

BIC R0,R1,#0x80 // Ro = R1&(~0x80) 
BICEQ R0,R1,R3
BICS R0,R1,R2
   N = Rd[31]
   Z = if Rd == 0 then 1 else 0
   C = shifter_carry_out
BICS  PC,R1,#0x0

總結
位運算
AND
ORR
EOR
BIC
有無S:

比較測試指令
比較指令:CMP
指令格式:
CMP ,
指令功能:
Rn -

CMP  R0,#0x80  
CMPEQ R0,R3
   N = ALU_OUT[31]
   Z = if ALU_out == 0 then 1 else 0
   C = NOT BorrowFrom(Rn - shifter_operand)
   V = OverflowFrom(Rn - shifter_operand)
cmp R1,#10 //R1-10 == 0 ,r1=10 z = 1
moveq r0,r1
bleq test  //這裡的eq,用的cmp R1,#10裡面的影響結果
  ...
test:
  ...

負值比較指令:CMN
指令格式:
CMN ,
指令功能:
Rn +

   CMN R0,#0x80 // R0 + 0x80
   CMN R1,#5 // R0 + 5 == 0 ? Z = 1
   BEQ SKIP //根據Z判斷是否為相等
   ....
SKIP:
   ...

位測試指令:TST
指令格式:
TST ,
指令功能:
Rn &
會自動影響NZCV,後面的指令可以根據NZCV來判斷結果

TST R0,#0x80
TESTEQ R0,R3
   N = ALU_out[31]
   Z = if ALU_out == 0 ...
   C shifter_carray_out
TXT R0,#0x1
ADDEQ R1,R2,R3
TST R1,R4

相等測試指令:TEQ
指令格式:
TEQ ,
指令功能:
Rn ^

TEQ R0,#0x80
TEQNE R0,R3
   N = ALU_out[31]
   Z = if ALU_out == 0  then 1 else 0
   C shifter_carray_out

比較
CMP -
CMN +
TST &
TEQ ^

總結
資料處理指令

  • 資料傳送(MOV,MVN)
  • 算術運算(ADD ADC SUB RSB RSC)
    進位:C=1 有進位,C = 0,無進位
    借位:C=0 有借位,C =1,無借位
  • 位運算(AND ORR EOR BIC)
  • 比較測試(CMP CMN TST TEQ)

一般格式:
操作碼{條件碼}S 目標暫存器,第一源運算元,第二源運算元

  1. 第一源運算元只能是暫存器
  2. 第二源運算元
    1,8點陣圖立即資料 (#rot ,8bit立即數,ROR)
    2,暫存器
    3,暫存器移位(LSL,LSR,ASR,ROR,RRX)

  3. .S
    1,目標暫存器為pC, CPSR = SPSR
    2,目標暫存器不是PC,根據運算結果影響CPSR的NZCV

  4. 資料傳送指令沒有第一源運算元

  5. 比較測試指令沒有目標暫存器,不加S,結果預設影響NZCV

案例
用匯編指令實現1-10累加和計算。
思路:用B跳轉指令構建迴圈,用比較指令跳出迴圈,用加法指令累加。

sum.s

    .text
    .global _start
    .global sum
    .code 32

 _start:
    mov r0,#10 //儲存迴圈次數
    mov r1,#0 //用來儲存結果 
 sum:
    add r1,r1,r0 //r1 = r1+r0
    subs r0,r0,#1 // r0--
    cmp r0,#0//比較R0 與 0 ,如果不等於0,Z位就會為0
    bne sum //條件跳轉,ne表示不等於,則執行sum,如果相等,執行 b  .
 sum_ok:
    b .
    .end

編譯、連結、除錯

arm-linux-as -g -o sum.o sum.s
arm-linux-ld -e _start,-o,sum sum.o
qemu-arm -g 1234 sum #除錯

用匯編指令求最大公約數?
20 12 8 = 20-12 4 = 12-8
5*4 4*3 4*2 4*1
R0=20,R1=12
while(R0!=R1){
if(R0>=R1){//cmp 預設影響NZCV
//beq
R0 = R0 - R1;//subcs
}else{
R1= R1-R0;//subcc
//b
}
}

gcd.s

    .text
    .code 32
    .global gcd //標號
gcd:
    //把兩個數先放到暫存器
    mov r0,#20 
    mov r1,#12 
loop:
    cmp r0,r1 
    //以下幾行相當於if .. else if ..
    beq boop_end
    subcs  r0,r0,r1 //如果cmp r0,r1條件滿足,執行本條;cs 表示無符號大於或等於
    subcc  r1,r1,r0 //如果cmp r0,r1條件不滿足,執行本條
    b loop //無條件跳轉
 boop_end:
    b   .
    .end