常用ARM指令1:數據處理指令
mov mvn
MOV(MOVE)指令可完成從另一個寄存器、被移位的寄存器或將一個立即數加載到目的寄存器
MOV R0,R1;R1的值傳到R0
MOV R3,#3 ;把常數3傳給R3
MVN( MOVE Negative)取反后再傳值,比MOV多了一步取反
MVN R0, #0 ;把0取反(即-1)傳給R0
MVN R1,R2 ;把R2的值取反傳給R1
算術指令
add sub rsb adc sbc rsc
ADD加法指令
ADD R0,R1,R2; R0=R1+R2
ADD R0,R1,#3 ;R0=R1+3
ADC帶進位加法指令,即除了加兩個數以外,還要把CPSR的C值也要帶進來
通常用於大數(超過32Bit整數)相加,這時單用ADD不能處理,必須折成兩步,其中一步用ADC.
以下是做64Bit的加法
ADDS R0,R1,R2; R0=R1+R2,ADDS中S表示把進位結果寫入CPSR
ADC R5,R3,R4 ;R5=R3+R4+C
邏輯指令
and orr eor bic
AND位與指令
AND R0,R1,R2; R0=R1 & R2
AND R0,R1,#0xFF ;R0=R1 & 0xFF
ORR位或指令
ORR R0,R1,R2; R0=R1 | R2
ORR R0,R1,#0xFF ;R0=R1 | 0xFF
TST測試某一位是否為1,並把結果寫入CPSR,供下一句使用
TST R1,#0xffe; 等同於if(R1 & 0xffe)
TST R1,#%1;測試最低位是否為1,%表示二進制
BIC清位操作
BIC R0,R0,#0xF; 等同於 R0 &=~(0xF)
BIC R0,R0,#%1011; 該指令清除 R0 中的位 0 1 3,其余的位保持; %表示是二進制,0x表示十六進制
比較指令
cmp cmn tst teq
CMP比較兩個操作數,並把結果存入CPSR供下一句語句使用
CMP R0,R1; 比較R0,R1
乘法指令
mvl mla umull umlal smull small
MUL R0,R1,R2 ;R0 = R1 × R2
MULS R0,R1,R2 ;R0 = R1 × R2,同時設置CPSR中的相關條件標志位
MLA R0,R1,R2,R3 ;R0 = R1 × R2 + R3
MLAS R0× R2 + R3,同時設置CPSR中的相關條件標志位
SMULL R0,R1,R2,R3 ;R0 = (R2 × R3)的低32位
;R1 = (R2 × R3)的高32位
加載/存儲指令 LDR,STR
LDR R0,[R1]; R1的值當成地址,再從這個地址裝入數據到R0 (R0=*R1)
LDR R1,=0x30008000 ; 把地址0x30008000的值裝入到R1中
STR R0,[R1] ; 把R0的值,存入到R1對應地址空間上(*R1 = R0)。
STR R0,=0x30008000 ;把R0中值存入到地址0x30008000
常用ARM指令2:cpsr訪問指令
mrs & msr
mrs用來讀psr,msr用來寫psr
CPSR寄存器比較特殊,需要專門的指令訪問,這就是mrs和msr。
常用ARM指令3:跳轉(分支)指令
b & bl & bx
b 直接跳轉(就沒打開算返回)
B main ;跳轉到標號為main地代碼處
bl branch and link,跳轉前把返回地址放入lr中,以便返回,以便用於函數調用
bx跳轉同時切換到ARM模式,一般用於異常處理的跳轉
常用ARM指令4:訪存指令
ldr/str & ldm/stm & swp
單個字/半字/字節訪問 ldr/str
多字批量訪問 ldm/stm
swp r1, r2, [r0]
swp r1, r1, [r0]
常用ARM指令5:軟中斷指令
swi(software interrupt)
軟中斷指令用來實現操作系統中系統調用
協處理器cp15操作指令
mcr & mrc
mrc用於讀取CP15中的寄存器
mcr用於寫入CP15中的寄存器
MRC & MCR的使用方法
mcr{<cond>} p15, <opcode_1>, <Rd>, <Crn>, <Crm>, {<opcode_2>}
opcode_1:對於cp15永遠為0
Rd:ARM的普通寄存器
Crn:cp15的寄存器,合法值是c0~c15
Crm:cp15的寄存器,一般均設為c0
opcode_2:一般省略或為0
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
8種后綴
ia(increase after)先傳輸,再地址+4
ib(increase before)先地址+4,再傳輸
da(decrease after)先傳輸,再地址-4
db(decrease before)先地址-4,再傳輸
fd(full decrease)滿遞減堆棧
ed(empty decrease)空遞減堆棧
fa(·······) 滿遞增堆棧
ea(·······)空遞增堆棧
四種棧
空棧:棧指針指向空位,每次存入時可以直接存入然后棧指針移動一格;而取出時需要先移動一格才能取出
滿棧:棧指針指向棧中最后一格數據,每次存入時需要先移動棧指針一格再存入;取出時可以直接取出,然后再移動棧指針
增棧:棧指針移動時向地址增加的方向移動的棧
減棧:棧指針移動時向地址減小的方向移動的棧
!的作用
ldmia r0, {r2 - r3}
ldmia r0!, {r2 - r3}
感嘆號的作用就是r0的值在ldm過程中發生的增加或者減少最后寫回到r0去,也就是說ldm時會改變r0的值。
^的作用
ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^
^的作用:在目標寄存器中有pc時,會同時將spsr寫入到cpsr,一般用於從異常模式返回。
偽指令的意義
偽指令不是指令,偽指令和指令的根本區別是經過編譯后會不會生成機器碼。
偽指令的意義在於指導編譯過程。
偽指令是和具體的編譯器相關的,我們使用gnu工具鏈,因此學習gnu環境下的匯編偽指令。
gnu匯編中的一些符號
@ 用來做注釋。可以在行首也可以在代碼后面同一行直接跟,和C語言中//類似
# 做注釋,一般放在行首,表示這一行都是注釋而不是代碼。
:以冒號結尾的是標號
. 點號在gnu匯編中表示當前指令的地址
# 立即數前面要加#或$,表示這是個立即數
常用gnu偽指令
.global _start @ 給_start外部鏈接屬性
.section .text @ 指定當前段為代碼段
.ascii .byte .short .long .word
.quad .float .string @ 定義數據
.align 4 @ 以16字節對齊
.balignl 16 0xabcdefgh @ 16字節對齊填充
偶爾會用到的gnu偽指令
.end @標識文件結束
.include @ 頭文件包含
.arm / .code32 @聲明以下為arm指令
.thumb / .code16 @聲明以下為thubm指令
最重要的幾個偽指令
ldr 大范圍的地址加載指令
adr 小范圍的地址加載指令
adrl 中等范圍的地址加載指令
nop 空操作