1、跳转指令
跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
1).使用专门的跳转指令。
2).直接向程序计数器PC写入跳转地址值,通过向程序计数器PC写入跳转地址值,可以实现
4GB
的地址空间中的任意跳转,在
跳转之前
结合使用 [
MOV LR, PC ]
等类似指令,可以保存将来的返回地址值,从而实现在
4GB
连续的线性地址空间的子程序调用。
ARM指令集中的跳转指令可以完成从当前指令
向前或后的
32MB
的地址空间的跳转,包括以下
4
条指令:
B
跳转指令
BL
带返回的跳转指令
BLX
带返回和状态切换的跳转指令
BX
带状态切换的跳转指令
==============================
(1)B
B指令的格式为:
B{条件} 目标地址
B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。
eg1: B Label ;
程序无条件跳转到标号Label处执行
eg2: CMP R1, #0
B
EQ
Label ;
当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行。
指令条件
(2)BL
BL
指令的格式:
BL{条件} 目标地址
BL是另一个跳转指令,
但跳转之前,会在寄存器R14中保存
PC
当前值
,因此,可以通过将
R14
的内容重新加载到
PC
中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。
BL Label
; 当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中。
(3)BLX
BLX
指令的格式为:
BLX 目的地址
BLX指令从ARM指令集跳转到指令集所指定的目标地址,
并将处理器的工作状态有
ARM
状态切换到
Thumb
状态,该指令同时将
PC
的当前内容保存到寄存器
R14
中
。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器和工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。
(4)BX
BX
指令的格式为:
BX{条件} 目的地址
BX指令跳转到指令中指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。
2、数据处理指令
数据处理指令可以分为
数据传送指令
、
算术逻辑运算指令
和
比较指令
等。
数据传送指令用于在
寄存器
和
存储器
之间进行数据的双向传输。
算术逻辑运算指令完成常用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。
(1)MOV指令
MOV
指令的格式为:
MOV{条件}{S} 目的寄存器, 源操作数
MOV指令完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
MOV R1, R0 ;将寄存器R0的值传送到寄存器R1
MOV PC, R14 ;将寄存器R14的值传送到PC,通常用于子程序返回
MOV R1, R0, LSL #3 ;将寄存器R0的值左移3位后传送到R1
(2)MVN指令
MVN
指令的格式为:
MVN{条件}{S} 目的寄存器, 源操作数
MVN指令可以完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。
与MOV指令不同之处是在传送之前按位取反了,即把一个被取反的值传送到目的寄存器中。
其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
MVN R0, #0xff
; R0 <= 0xffffff00
(3)CMP指令
CMP
指令的格式为:
CMP{条件} 操作数1, 操作数2
CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,
同时更新CPSR中条件标志位的值。
该指令进行一次减法运算,但
不存储结果,只更改条件标志位
。
标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。
指令示例:
CMP R1, R0 ; 将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位
CMP R1, #100 ; 将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位
(4)TST指令
TST
指令的格式为:
TST{条件} 操作数1, 操作数2
TST指令用于把一个寄存器的内容合并另一个寄存器的内容或立即数进行
按位与运算
,并根据运算结果跟新CPSR中条件标志位的值。
操作数1是要测试的数据,而操作数2是一个位掩码,根据测试结果设置相应标志位。
当位与结果为0时,EQ位被设置。
指令示例:
TST R1, #%1 ;用于测试在寄存器R1中是否设置了最低为(%表示二进制数)
(5)ADD指令
ADD
指令的格式为:
ADD{条件}{S} 目的寄存器, 操作数1, 操作数2
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。
操作数1应是一个
寄存器
,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。
指令示例:
ADD R0, R1, R2 ;R0 = R1 + R2
ADD R0, R1, #256 ;R0 = R1 + 256
ADD R0, R2, R3,
LSL
#1 ;R0 = R2 + (R3
<< 1)
(6)SUB指令
SUB
指令的格式为:
SUB{条件}{S} 目的寄存器 操作数1, 操作数2
SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。
操作数1应是一个
寄存器
,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。
指令示例:
SUB R0, R1, R2 ;R0 = R1 - R2
SUB R0, R1, #256 ;R0 = R1 - 256
SUB R0, R2, R3,
LSL
#1 ;R0 = R2 - (R3
<< 1)
(7)AND指令
AND
指令的格式为:
AND{条件}{S} 目的寄存器 操作数1, 操作数2
AND指令用于在两个操作数上进行
逻辑与
运算,并把结果放置到目的寄存器中。
操作数1应是一个
寄存器
,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。
该指令常用于屏蔽操作数1的某些位。
AND R0, R0, #3 ; 该指令
保持R0的0、1位,其余位清零。
(8)ORR指令
ORR
指令的格式为:
ORR{条件}{S} 目的寄存器 操作数1, 操作数2
ORR指令用于在在两个操作数上进行
逻辑或
运算,并把结果放置到目的寄存器中。
操作数1应是一个
寄存器
,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。
该指令常用于设置操作数1的某些位。
ORR R0, R0, #3 ;该指令设置R0的0、1位,其余位保持不变。
9)BIC指令
BIC
指令的格式为:
BIC{条件}{S} 目的寄存器 操作数1, 操作数2
BIC指令用于清除操作数1中的某些位,并把结果放置到目的寄存器中。
操作数2为32位的掩码,如果掩码中设置了某一位为1,则清楚这一位。
例:
BIC R0, R0, #%1011
; 将R0的0,1,3位清零,其余位不变。
(10)MUL指令
MUL
指令的格式为:
MUL{条件}{S} 目的寄存器 操作数1, 操作数2
MUL指令完成将操作数1与操作数2的
乘法
运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。
其中,操作数1和操作数2均为32位的有符号数或无符号数。
MUL R0, R1, R2 ;R0 = R1 x R2
MULS R0, R1, R2 ;R0 = R1 x R2, 同时设置CPSR中的相关条件标志位
3、程序状态寄存器访问指令
ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用状态寄存器之间传送数据。
(1)MRS指令
MRS
{条件} 通用寄存器, 程序状态寄存器(CPSR或SPSR)
MRS指令用于
将程序状态寄存器的内容传送到通用状态寄存器中
。
该指令一般用在以下几种情况:
1)当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
2)当在异常处理或进程切换时,需要保存程序寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
MRS R0, CPSR ; 传送CPSR的内容到R0
MRS R0, SPSR ; 传送SPSR的内容到R0
(2)MSR指令
MSR
{条件} 程序状态寄存器(CPSR或SPSR)_<域>, 操作数
MSR指令用于
将操作数的内容传送到状态寄存器的特定域中
。其中,操作数可以位通用寄存器或立即数。
<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域
:
位[31 : 24] 为条件标志位域,用f表示;
位[23 : 16] 为状态位域,用s表示
位[15 : 8] 为扩展位域,用x表示
位[ 7 : 0] 为控制位域,用c表示
该指令通常用于恢复或改变程序状态寄存器的吧内容,在使用时,一般要在MSR指令中指明将要操作的域。
指令示例:
MSR CPSR, R0 ;传送R0的内容到CPSR
MSR SPSR, R0 ;传送R0的内容到SPSR
MSR CPSR_c, R0 ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域。
4、加载/存储指令
ARM微处理器支持加载/存储指令用于在
寄存器和存储器之间
传送数据,
加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。
(1)LDR指令
LDR
指令的格式为:
LDR
{条件} 目的寄存器, <存储器地址>
LDR
指令用于从
存储器
中将一个32位的字数据传送到目的寄存器中。
该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。
示例:
LDR R0, [R1]
将存储器地址为R1的字数据读入寄存器R0。
LDR R0, [R1, R2]
将存储器地址为R1 + R2的字数据读入寄存器R0。
LDR R0, [R1, #8]
将存储器地址为R1 + 8的字数据读入寄存器R0。
LDR R0, [R1, R2]
!
将存储器地址为R1 + R2的字数据读入寄存器R0,并将新地址R1 + R2写入R1。
LDR R0, [R1, #8]
!
将存储器地址为R1 + 8的字数据读入寄存器R0,并将新地址R1 + 8写入R1。
LDR R0, [R1], R2
将存储器地址为R1的字数据读入寄存器R0,并将新地址R1 + R2写入R1。
LDR R0, [R1, R2, LSL #2]
!
将存储器地址为R1 + R2 x 4的字数据读入寄存器R0,并将新地址R1 + R2 x 4写入R1。
LDR R0, [R1], R2, LSR #2
将存储器地址为R1的字数据读入寄存器R0,并将新地址R1 + R2 x 4写入R1。
(2)LDRB指令
LDRB
指令的格式为:
LDRB
{条件} 目的寄存器, <存储器地址>
LDR
指令用于从
存储器
中将一个
8
位的
字数据传送到目的寄存器中,
同时将寄存器的高24位清零
。
该指令通常用于从存储器中读取
8
位的字数据到通用寄存器,然后对数据进行处理。
指令示例:
LDRB R0, [R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0, [R1, #8] ;将存储器地址为R1 + 8的字节数据读入寄存器R0,并将R0的高24位清零。
(3)LDRH指令
LDRH
指令的格式为:
LDRH
{条件}
H
目的寄存器, <存储器地址>
LDRH
指令用于从
存储器
中将一个
16
位的
半字数据传送到目的寄存器中,
同时将寄存器的高16位清零
。
该指令通常用于从存储器中读取
16
位的半字数据到通用寄存器,然后对数据进行处理。
指令示例:
LDRH R0, [R1] ;将存储器地址为R1的半字节数据读入寄存器R0,并将R0的高16位清零。
LDRH R0, [R1, R2] ;将存储器地址为R1 + R2的半字节数据读入寄存器R0,并将R0的高16位清零。
(4)STR指令
STR
指令的格式为:
STR
{条件} 源寄存器, <存储器地址>
STR
指令用于
从源寄存器
中将一个32位的字数据传送
到存储器
中。
指令示例:
STR R0, [R1], #8 ;将R0中的字节数据写入以R1为地址的存储器中,并将新地址R1 + 8写入R1。
STR R0, [R1, #8] ;将R0中的字节数据写入以R1 + 8为地址的存储器中。
5、
批量
加载/存储指令
ARM微处理器所支持的批量数据加载/存储指令可以一次在
一片连续的
存储单元和多个寄存器之间传送数据,
批量加载指令用于将一片连续的
存储器
中的数据传送到多个
寄存器
,批量数据存储指令则完成
相反
的操作。
常用的加载存储指令如下:
LDM 批量数据加载指令
STM 批量数据存储指令
(1)LDM指令
LDM
指令的格式为:
LDM
{条件}{类型} 基址寄存器{!}, 寄存器列表{^}
LDM
{或
STM
}指令用于从由
基址寄存器所指示的一片连续存储器
到
寄存器列表所指示的多个寄存器
之间传送数据,
该指令的常见用途是将多个寄存器的内容入栈或出栈。
其中,{类型}为以下几种情况:
IA 每次传送后地址加1
IB 每次传送前地址加1
DA 每次传送后地址减1
DB 每次传送前地址减1
FD 满递减堆栈
ED 空递减堆栈
FA 满递增堆栈
EA 空递增堆栈
指令示例:
STMFD R13!, {R0, R4-R12, LR} ;将寄存器列表中的寄存器(R0, R4到R12, LR)存入堆栈。
LDMFD R13!, {R0, R4-R12, PC} ;将堆栈内容恢复到寄存器(R0, R4到R12, LR)。
{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15
,寄存器列表可以为R0~R15的任意组合。
{^}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除正常的数据传送之外,
还将SPSR复制到CPSR
。
6、数据交换指令
ARM微处理器所支持数据交换指令能在
存储器和寄存器之间交换数据
。数据交换指令有如下两条:
SWP 字数据交换指令
SWPB 字节数据交换指令
(1)SWP指令
SWP
指令的格式如下:
SWP
{条件} 目的寄存器, 源寄存器1, [源寄存器2]
SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据寄存器传送到源寄存器2所指向的存储器中。
显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
指令示例:
SWP R0, R1, [R2];将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指向的存储器单元。
SWP R0, R0, [R1] ;该指令完成将R1所指向的存储器中的数据与R0中的数据交换。
7、移位指令
ARM微处理器支持数据的移位操作,
移位操作在ARM指令集中不作为单独的指令使用,它只能作为指令格式中是一个字段
,
在汇编语言中表示为指令中的选项。
移位操作包括如下6中类型,
ASL
和
LSL
是等价的,可以自由互换:
LSL
逻辑左移
ASL
算术左移
LSR
逻辑右移
ASR
算术右移
ROR
循环右移
(1)LSL 操作
LSL
操作的格式为:
通用寄存器,
LSL
操作数
LSL
可完成对通用寄存器中的内容进行逻辑左移操作,按操作数所指定的数量向左移位,低位用零来填充。
其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
操作示例:
MOV R0, R1, LSR#2 ;将R1中的内容左移两位后传送到R0中。
(2)ROR 操作
ROR
操作的格式为:
通用寄存器,
ROR
操作数
ROR
可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,
左端用右端移出的位来填充
。
其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
显然,当进行32位的循环右移操作时,通用寄存器中的值不改变。
操作示例:
MOV R0, R1, ROR#2 ;将R1中的循环右移两位后传送到R0中。
8、异常产生指令
ARM微处理器所支持的异常指令有如下两条:
SWI
软件中断指令
BKPT
断点中断指令
(1)SWI指令
SWI
操作的格式为:
SWI
{条件} 24位的立即数
SWI
指令用于产生软件中断,以便用户程序能调用操作系统的系统API。
操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位立即数指定用户程序调用的API类型。
指令示例:
SWI 0x02 ;该指令调用操作系统编号为02的系统例程。
所有练习程序如下:< test1.S >
;寻址方式,使用AXD调试时,可使用单步调试(F10)
;使用AXD的processor views-->register查看寄存器变化
;使用AXD的processor views-->memory查看内存的值
;使用AXD的processor views-->disassembly查看反汇编代码
GBLA Test1 ;声明一个全局的数学变量,变量名为Test1
GBLL Test2 ;申明一个全局的逻辑变量,变量名为Test2
Test1 SETA 0x3 ;将变量Test1赋值为3,注意书写格式,需要顶格写
Test2 SETL {TRUE} ;将变量Test2赋值为TRUE
;EQU伪指令
COUNT EQU 0x30003100 ; 定义一个变量,地址为0x30003100
AREA Example1,CODE,READONLY ; 声明代码段Example1
ENTRY ; 标识程序入口
CODE32 ; 声明32位ARM指令
START
;立即寻址
MOV R0,#0 ; R0 <= 0,将立即数0x00存入寄存器R0,可通过AXD的processor views-->register查看
ADD R0,R0,#1 ; R0 <= R0 + 1
ADD R0,R0,#0x3f ; R0 <= R0 + 0x3f
;寄存器寻址
MOV R1,#1 ; R1 <= 1,将立即数0x01存入寄存器R1
MOV R2,#2 ; R2 <= 2,将立即数0x02存入寄存器R2
ADD R0,R1,R2 ; R0 <= R1+R2,将寄存器R1和R2的内容相加,其结果存放在寄存器R0中
;寄存器间接寻址
LDR R1,=COUNT ; R1 <= COUNT,将存储器地址放入寄存器R0
;MOV R0,#0x12 ; R0 <= 0x12,MOV指令目地操作数只能是8位
LDR R0,=0x12345678
STR R0,[R1] ; [R1] <= R0,将寄存器R0的内容存入寄存器R1所指向的存储器
;即设置COUNT为0x12345678,
;STR指令用于从源寄存器中将一个32位的字数据传送到存储器中
;可通过AXD的processor views-->memory查看0x30003100的值
;基址变址寻址
LDR R1,=COUNT ;将存储器地址0x30003100放入寄存器R1
LDR R2,=(COUNT+4) ;将存储器地址0x30003104放入寄存器R1
MOV R3,#0x12 ;将立即数0x12存入寄存器R3
STR R3,[R2] ;将寄存器R3的内容存入寄存器R2所指向的存储器
LDR R4,[R1,#4] ;将寄存器R1的内容加上4所指向的存储器的字存入寄存器R4
;多寄存器寻址
LDR R1,=COUNT ;将存储器地址0x30003100放入寄存器R1
LDMIA R1,{R5,R6} ;R5 <= [R1],R6 <= [R1+4]
;相对寻址
BL NEXT ;跳转到子程序NEXT处执行,注意使用F8(step in)
NOP
NOP
;跳转指令(B)
B label1 ;跳转到子程序label1处执行
NOP
NOP
NOP
NEXT
MOV R0,LR
NOP
NOP
NOP
MOV PC,LR ;从子程序返回
label1
NOP
NOP
NOP
;跳转指令(BL)
BL lable2 ;跳转到子程序label2处执行
NOP
NOP
;MOV指令
MOV R0,#0x12 ;R0=0x12
MOV R1,R0 ;R1=R0
MOV R1,R0,LSL#3 ;R1=R0<<3
;MVN指令
MVN R0,#0xff ; R0 = 0xfffff00
MVN R0,#0xA0000007 ; 0xA0000007的反码为0x5FFFFFF8
;CMP指令(使用AXD查看CPSR)
MOV R0,#1
MOV R1,#2
CMP R0,R1 ;若R0>R1,则置R0=3,若R0<=R1,则置R1=3
MOVHI R0,#3 ;根据CPSR条件标志位中的HI(无符号大于)判断,若R0>R1,则R0=3
MOVLS R1,#3 ;根据CPSR条件标志位中的LS(无符号小于或等于)判断,R0<=R1,则R1=3
;TST指令,测试R5的bit23是否为1,若是则置R5=0x01,不是则置R5=0x00
LDR R5,=0xffffffff
TST R5,#(1<<23) ;当bit23位为1时,CPSR EQ位被设置
MOVEQ R5,#0x00
MOVNE R5,#0x01
;ADD指令
MOV R1,#1
MOV R2,#2
MOV R3,#3
ADD R0,R1,R2 ;R0=R1+R2
ADD R0,R1,#256 ;R0=R1+256
ADD R0,R2,R3,LSL#1 ;R0=R2+(R3<<1)
;SUB指令
MOV R1,#100
MOV R2,#8
SUB R0,R1,R2 ;R0=R1-R2
SUB R0,R1,#55 ;R0=R1-256
;AND指令
MOV R0,#0xff
AND R0,R0,#3 ;逻辑与运算,R0 = R0 & 3
;ORR指令
MOV R0,#0xff
ORR R0,R0,#3 ;逻辑或运算,R0 = R0 | 3
;BIC指令
MOV R0,#0x77
BIC R0,R0,#0x0b ;将R0的bit0,bit1,bit3清零,其余位不变
;MUL指令
MOV R1,#10
MOV R2,#20
MUL R0,R1,R2 ;R0=R1*R2
;MRS指令(将CPSR或者SPSR的内容传送到通用寄存器)
MRS R0,CPSR ;传送CPSR的内容到R0
MRS R1,SPSR ;传送SPSR的内容到R1
;LDR指令
LDR R1,=0x30003100 ;R1=0x30003100,使用AXD的processor views-->memory查看内存的值
LDR R0,[R1] ;R0=[R1]
LDR R0,[R1,#4] ;R0=[R1+4]
;LDRB,LDRH指令
LDR R1,=0x30003100
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零
LDRH R2,[R1] ;将存储器地址为R1的半字数据读入寄存器R2,并将R2的高16位清零
;STR指令,内存地址0x30003100=0xab
LDR R1,=0x30003100
MOV R0,#0xab
STR R0,[R1] ;将R0中的字数据写入以R1为地址的存储器中
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中
;LDM,STM指令
LDR R1,=0x30003100
LDMIA R1,{R5,R6} ;R5 = [R1],R6 = [R1+4]
MOV R2,#0x33
MOV R3,#0X44
STMIA R1,{R2,R3} ;[R1]=R2,[R1+4]=R2
;SWP指令
SWP R0,R0,[R1] ; 该指令完成将R1所指向的存储器中的字数据与R0中的字数据交换
;移位指令
MOV R1,#4
MOV R0,R1,LSL#2 ;R0=R1<<2
MOV R1,#3
MOV R0,R1,ROR#2 ;将R1中的内容循环右移两位后传送到R0中
;汇编控制伪指令,while指令
WHILE Test1<10
MOV R0,#Test1
MOV R1,#1
Test1 SETA Test1+1
WEND
;汇编控制伪指令,IF指令
IF Test2 = {TRUE}
MOV R0,#1
MOV R1,#2
ELSE
MOV R0,#0
MOV R1,#0
ENDIF
B out
lable2
MOV R0,LR ;查看R14
NOP
NOP
MOV PC,LR ;从子程序返回
out
NOP
END