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]