ARM所有常用指令的實例與說明:
程序跳轉類指令:
====================
BX,
語法: bx Rn
此指令執行程序跳轉,執行後,cpu從Rn這個寄存器裡面所存的內存地址處開始繼續執行。由於是跳轉,因此也會同時刷新管道線。另外,如果此Rn的最低位為1的話,隨後的指令將被譯作thumb指令,如果最低位為0的話,隨後的指令將被譯作arm32位指令。因此,此指令可以用於在32位arm指令與16位thumb指令之間進行跳轉。
32位代碼轉入16位代碼執行:
16位代碼轉入32位代碼執行:
B, BL 指令,
語法: 指令 表達式/label
B指令就直接跳轉指定的地方,bl跳轉到指定的地方之前還要把當前pc保存在lr寄存器裡面。
die_loop:
b die_loop 這樣就構成了死循環
bl add 保存當前pc到lr,然後調用add函數,
數據處理類指令:
====================
mov, mvn指令:
語法: 指令 目標寄存器, 操作數
mov指令把操作數拷貝到目標寄存器裡面。操作數可以是:寄存器,或者立即數表達式,
例如:
mov r0, r1 # 把r1賦給r0
mov r2, #7
mov r0, r1, LSL r2 把r1左移r2位後賦給r0
mov r2, #100 # 把立即數100賦給r2
mvn指令把操作數按位取反之後把值賦給目標寄存器。
例如:
mov r0, r1 # 表示把r1裡面的值按位取反後賦給r0
cmp, cmn, teq, tst, 指令:
語法: 指令 寄存器, 操作數
操作數可以是:寄存器,或者立即數表達式
這四條指令都是讓後面的寄存器於操作數執行相應的操作後根據結果設定cpsr寄存器裡面的相應位的值。
cmp指令把寄存器和操作數相減,根據結果設定cpsr。用於比較大小。
例如:循環100次
mov r0, #0
loop100:
add r0, r0, #1
cmp r0, #100
ble loop100
cmn指令把寄存器和操作數想加,根據結果設定cpsr。用於看兩個數只和會不會有進位。
teq指令把寄存器和操作數進行按位異或,根據結果設定cpsr。用於測試兩個數是否相等。
tst指令把寄存器和操作數進行按位相與,根據結果設定cpsr。用於測試某位是否為1。
這四條指令在執行期間都只是對寄存器和操作數進行操作,並不回寫。
and, eor, sub, rsb, add, adc, sbc, rsc, orr, bic指令:
語法:指令 Rd, Rn, Op2
操作數可以是:寄存器,立即數
and 指令對Rn和Op2按位與操作之後把結果賦值給Rd.
eor 指令對Rn和Op2按位異或操作之後把結果賦值給Rd.
sub 指令對Rn和Op2進行減操作之後把結果賦值給Rd.
rsb 指令對Op2和Rn進行減操作之後把結果賦值給Rd.
add 指令對Rn和Op2進行加操作之後把結果賦值給Rd.
adc 指令對Rn和Op2加操作並且加上cpsr寄存器中的C位的值之後把結果賦值給Rd.
sbc 指令執行Rn-op2-1+進位位之後把結果賦值給Rd。
rsc 指令執行Op2-Rn-1+近位位之後把結果賦值給Rd.
orr 指令對Rn和Op2按位或操作之後把結果賦值給Rd.
bic 指令執行對Op2先按位取反之後再與Rn進行按位與操作,之後把結果賦值給Rd,用於對Rd中的某位置0.
mrs, msr指令:
語法: mrs Rd, <psr>
msr <psr>, Rm
msr <psrf>, Rm
msr <psrf>, #expression
psr可以是cpsr, spsr, mrs用於讀取psr寄存器裡面的值然後賦值給Rd.
msr用於存儲Rm寄存器裡面的值進入psr裡面。
msr <psrf>, Rm只修改psr裡面的標志位。
mul, mla指令:
語法: mul Rd, Rm, Rs
mla Rd, Rm, Rs, Rn
mul指令對Rm和Rs執行乘操作之後把值賦給Rd。 Rd = Rm * Rs.
mla指令對Rd和Rs執行乘操作之後並加上Rn後賦值給Rd. Rd = Rm * Rs + Rn。
mull, mlal指令:
語法: umull RdLo, RdHi, Rm, Rs :把Rm和Rs當作32位無符號數執行乘法操作,然後把結果的低32位賦給RdLo, 高32位賦給RdHi
umlal RdLo, RdHi, Rm, Rs :把Rm和Rs當作32位無符號數執行乘法操作,再加上由RdHi和RdLo組成的64位數,然後把結果的低32位賦給RdLo, 高32位賦給RdHi
smull RdLo, RdHi, Rm, Rs :把Rm和Rs當作32位有符號數執行乘法操作,然後把結果的低32位賦給RdLo, 高32位賦給RdHi
smlal RdLo, RdHi, Rm, Rs :把Rm和Rs當作32位有符號數執行乘法操作,再加上由RdHi和RdLo組成的64位數,然後把結果的低32位賦給RdLo, 高32位賦給RdHi
ldr, str指令:
語法:<ldr/str>{b} Rd, <Address>
ldr用於從內存中加載數據到寄存器。
str用於存儲寄存器中的數據到內存中。
例子:
.LC:
ldr r0, .LC :表示把.LC所處內存地址裡面的4個字節值賦給r0 (這種情況需要此命令與標簽在同一段內)
ldr r0, =.LC :表示直接把.LC所處的地址賦給r0
ldr r0, [r1] : 表示把把r1所代表的內存地址裡面的值賦給r0
ldr r0, [r1, #8] : 表示r1加上8個字節代表的內存地址裡面的值賦給r0
ldr r0, [r1, #8]! : 表示r1加上8個字節代表的內存地址裡面的值賦給r0, 然後把r1 = r1 + 8
ldr r0, [r1], #4 : 表示把r1所代表的內存地址裡面的值賦給r0, 之後, r1 += 4
ldr r0, [r1, r2, LSL #2] :表示把r1+r2 * 4所代表的內存地址裡面的值賦給r0
str r0, [r1, r2] : 把r1 + r2所代表的內存地址裡面的值賦入r0
str r0, [r1, r2]! : 把r1 + r2所代表的內存地址裡面的值賦入r0, r1 = r1 + r2
ldm, stm指令:
語法: <ldm/stm><ed|fd|ea|fa> Rn{!}, <Rlist>{^}
Rlist, 表示寄存器列表。比如{r0, r2, r5-r7,r9 }
{!}, 表示執行完ldm或stm之後是否對Rn進行回寫。
{^}, 表示恢復spsr中的值到cpsr。(一般用於返回以前模式)
寄存器列表中的數據在內存中將被存放的順序為低寄存器對應低內存地址的順序存放。
stm操作始終與所指定的棧的方向保持相同,ldm相反。stm就相當於壓棧,ldm就相當於退棧。
stm表示把寄存器的數據存入內存
ldm表示把內存中的數據加載到寄存器上。
例如:
ldmfd sp, {r0,r1,r2} 表示把sp所指的內存地址開始的12個字節分別賦值給r0,r1,r2。
ldmfd sp!, {r0,r1,r2} 表示把sp所指的內存地址開始的12個字節分別賦值給r0,r1,r2,之後sp = sp + 12
ldmfd sp!, {r15}^ 表示把sp棧所指的4個字節裡面的值賦給r15, 同時把spsr賦值給cpsr,並且sp += 4
stmfd sp, {r0, r1, r2} 表示把r2,r1,r0按照sp所指地址遞減存儲。也就相當於下面3條指令:
str r2, [sp, #-4]
str r1, [sp, #-8]
str r0, [sp, #-12]
stmfd sp!, {r0, r1, r2} 表示把r2,r1,r0按照sp所指地址遞減存儲。並且把sp = sp - 12,也就相當於下面4條指令:
str r2, [sp, #-4]
str r1, [sp, #-8]
str r0, [sp, #-12]
sub sp, sp, #12
特殊用法:
stmfd sp!, {r0-r15}^ : 表示把用戶模式下面的r0-r15寄存器存在當前模式下面的sp所指向的棧中。
stmfd sp!, {r0-r14}^ : 表示把用戶模式下面的r0-r14寄存器存在當前模式下面的sp所指向的棧中。用於進程切換的時候保存用戶模式下面的寄存器。
ldmfd sp!, {r0-r14}^ : 寄存器列表這裡面不帶有r15(pc), 表示把當前模式下面sp所指的棧中的15個int拷貝用戶模式下面的r0-r14。這個用於恢復進程狀態。
swp指令:
語法: <swp><b/h> Rd, Rm, [rn]
swp指令執行單字節或單字的內存於寄存器的數據交換原子操作。把rn所指內存裡面的值賦值給Rd, 然後把R1存入R2所指的內存。經常用於內核中實現控制互斥與信號等功能。
例如:
swp r0, r1,[r2] :表示把r2所指的內存地址裡面的值賦值給r0, 然後把r1存入r2所指內存地址。相當於下面2條指令的原子操作。
ldr r0, [r2]
str r1, [r2]