嵌入式Linux ARM汇编(三)——ARM汇编指令
2019-07-12 19:00发布
生成海报
一、ARM汇编语言基本结构
AREA Init, CODE, READONLY
ENTRY
Start
LDR R0, =0x3FF5000
LDR R1, 0xFF
STR R1, [R0]
LDR R0, =0x3FF5008
LDR R1, 0x01
STR R1, [R0]
... ... ... ... ... ...
END
二、ARM处理器寻址方式
寻址方式是根据指令中给出的地址码字段来实现寻找真实操作数地址的方式。ARM处理器有九种寻址方式,寄存器寻址、立即数寻址、寄存器偏移寻址为数据处理指令操作数寻址方式,寄存器间接寻址、基址寻址、多寄存器寻址、堆栈寻址、相对寻址为存储器访问指令操作数寻址方式。
1、寄存器寻址
操作数的值存在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取出寄存器值操作。例如:
MOV R0,R1
SUB R0,R1,R2
2、立即寻址
立即寻址指令中的操作码字段部分后面的地址码部分就是操作数本身,即数据包含在指令当中。例如:
MOV R0,#0xff
立即数要以“#”为前缀,十六进制以“0x”表示
3、寄存器偏移寻址
寄存器偏移寻址是ARM指令集特有的寻址方式,当第2操作数是寄存器,在执行操作之前,可以做一次移位操作。
MOV R0,R2,LSL #3
ANDS R1,R1,R2,LSL R3
4、寄存器间接寻址
寄存器间接寻址指令中的地址码给出的是一个通用寄存器的编号,所需的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。
LDR R1,[R2] ;将R2指向的单元中的数据保存再R1中
SWP R1,R1,[R2] ;将寄存器R1的值和R2指向的单元中进行内容交换
5、基址寻址
基址寻址就是将基址寄存器的内容与指令中给出的偏移量进行相加,形成操作数的有效地址。基址寻址用于访问基址附近的存储单元,常用于查表、数组操作以及功能不见寄存器访问等。
LDR R2,[R3,#0x0c] ;读取R3
0x0c地址指向的存储单元的内容,放入R2
STR R1,[R0,#-4]! ;先R0=R0-4,然后把R1的值寄存到R0所指向的单元中
LDR R1,[R0,R3,LSL #1] ;将R0 R3*2地址上的单元的内容读出,并存入R1中
6、多寄存器寻址
多寄存器寻址即一次可传送几个寄存器的值,允许一条指令传送16个寄存器的任何子集或所有的存储器。
LDMIA R1!,{R2-R7,R12};将R1指向的单元中的数据读出到R2---R7、R12中(R1自自动
)
STMIA R0!,{R2-R7,R12};将R2---R7、R12中的数据一次读入到R0指向的单元中(R0自动
)
7、堆栈寻址
堆栈是一种按特定顺序进行存取的存储区,操作顺序分为“先进后出”和“后进先出”,堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向的存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。
STMFD SP!,{R1-R7,LR} ;将R1---R7、LR入栈。满递减堆栈
LDMFD SP!,{R1-R7,LR} ;数据出栈,放入R1---R7、LR寄存器,满递减堆栈
8、块拷贝寻址
多寄存器传送指令用于将一块数据从存储器的某一位置拷贝到另一位置。
STMIA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中。
;存储指针在保存第一个值之后增加,
;增长方向为向上增长。
STMIB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中。
;存储指针在保存第一个值之前增加,
;增长方向为向上增长。
9、相对寻址
相对寻址是基址寻址的一种变通。由程序计数器PC提供基址地址,指令中的地址码字段为偏移量。两者相加后得到的地址即为操作数的有效地址。
三、指令格式
ARM指令的基本格式:
[][S] , {,operand2}
opcode:指令助记码,如:MOV
con:执行条件,如NE,EQ
S:是否影响CPSR寄存器的值,设置时影响CPSR
Rd:目标寄存器
Rn:第一个操作数的寄存器
operand2:第二个操作数
条件码表
四、ARM存储器访问指令
ARM处理器是加载/存储体系结构的典型RISC处理器,对存储器的访问只能用加载和存储指令实现。ARM的加载/存储指令可以实现字、半字、字节操作。
1、LDR和STR
加载/存储字和无符号字节指令。使用单一数据传送指令来装载和存储单一字节或字的数据。LDR指令用于从内存中读取数据放入内存中,STR指令用于将寄存器中的数据保存到内存中。
指令格式如下:
LDR[cond][T] Rd,<地址>;
加载指定地址上的数据(字),放入Rd中
STR[cond][T] Rd,<地址>;
存储数据(字)到指定地址的存储单元,要存储的数据在Rd中
LDR[cond]B[T] Rd,<地址>;加载字节数据,放入Rd中,Rd低字节有效
STR[cond]B[T] Rd,<地址>;存储字节数据,要存储的数据在Rd中
指令T表示在处理器特权模式下,存储系统也将访问看做是在用户模式下。
STR R0,[R1],#8;将R0中内容写入R1为地址的内存中,并将新地址R1+8写入R1。
STR R0,[R1,#8];将R0中的字数据写入以R1+8为地址的存储器中。
LDR/STR指令寻址非常灵活,由两部分组成,一部分为基址寄存器,可以是任一通用寄存器,另一部分为地址偏移量,由以下三种格式:
a、立即数
立即数可以是一个无符号数值,这个数值可以加到基址寄存器或由基址寄存器减去,例如:
LDR R0,[R1,#0x12];将R1+0x12地址处的数据读出保存到R0寄存器中
LDR R0,[R1,#-0x12];将R1-0x12地址处的数据读出保存到R0寄存器中
LDR R0,[R1];将R1地址处的数据读出保存到R0寄存器中
b、寄存器
寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个值,例如:
LDR R0,[R1,R2];将R1+R2地址处的数据读出,保存到R0寄存器中
LDR R0,[R1,-R2];将R1-R2地址处的数据读出,保存到R0寄存器中
c、寄存器及移位常数
基址寄存器加上或减去寄存器移位后的值
LDR R0,[R1,R2,LSL#2];将R1+R2*4地址处的数据读出,保存到寄存器R0
LDR R0,[R1,-R2,LSL#2];将R1-R2*4地址处的数据读出,保存到寄存器R0
LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。 该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目 的地址,从而可以实现程序流程的跳转。
LDRH指令的格式为:
LDR{条件}H 目的寄存器,<存储器地址>
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。 该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作 目的地址,从而可以实现程序流程的跳转。
STRB指令的格式为:
STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
STRH指令的格式为:
STR{条件}H 源寄存器,<存储器地址>
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。
应用示例:
GPIO设置:
GPIO_BASE EQU 0xE0028000;定义GPIO寄存器的基地址
LDR R0,=GPIO_BASE
LDR R1,=0x00FFFFFF00
STR R1,[R0,#0x0C];将0xE002800C地址的值设为0x00FFFFFF00
MOV R1,0x00F00000
STR R1,[R0,#0x04];将0xE0028004地址的值设为0x00F00000
2、LDM和STM
批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据,指令格式如下:
LDM[cond]<模式> Rn[!],reglist{^}
STM[cond]<模式> Rn[!],reglist{^}
模式有八种:
IA 每次传送后地址加4;
IB 每次传送前地址加4;
DA 每次传送后地址减4;
DB 每次传送前地址减4;
FD 满递减堆栈;
ED 空递减堆栈;
FA 满递增堆栈;
EA 空递增堆栈;
{!}为可选后缀,若选用该后缀,则当数据 传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。
{∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表 示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
指令示例:
STMFD R13!,{R0,R4-R12,LR} ;将寄存器列表中的寄存器(R0,R4到R12,LR)存入堆栈。
LDMFD R13!, {R0,R4-R12,PC}^ ;将堆栈内容恢复到寄存器(R0,R4到R12,PC),SPSR复制到CPSR
LDM/STM用途是现场保护、数据复制、参数传送
3、SWP
寄存器和存储器交换指令,指令格式:
SWP[cond][B] Rd,Rm,[Rn]
将Rn的值为地址的内存单元的值读取到Rd寄存器中,同时将寄存器Rm的值写入该内存单元。
如果有B,则交换字节,否则交换32位字;
五、ARM数据处理指令
数据处理指令分为数据传送指令、算数逻辑运算指令、比较指令
数据处理指令只能对寄存器的内容进行操作
1、数据传送指令
A、MOV
MOV指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S 时指令不更新CPSR中条件标志位的值。
指令格式:
MOV[con][S] Rd,operand2
MOV R0,#0x04
MOV R0,R1
MOVS R3,R2,LSL#2
MOV PC,LR;PC=LR,子程序返回
B、MVN
MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。指令格式:
MOV[con][S] Rd,operand2
MVN R0,R1
MVN R2,#0xFF;R2位0xFFFFFF00
2、算数逻辑运算指令
A、ADD加法运算指令
指令格式:
ADD[con][S] Rd,Rn,operand2
将operand2数据与Rn的值相加,结果保存到Rd寄存器
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
ADD R0,R1,R2
ADD R0,R1,#0x12
ADDS R0,R1,R2,LSL#2
B、SUB减法运算指令
SUB[con][S] Rd,Rn,operand2
用寄存器Rn的值减去operand2,结果保存在Rd中,指令格式:
SUBS R0,R0,#1
SUBS R0,R1,R2
RBS逆向减法指令
用寄存器operand2减去Rn,结果保存到Rd中,指令格式:
RBS[con][S] Rd,Rn,operand2
RSB R0,R1,#0x100;R0=0x100-R1
C、ADC带进位加法指令
将operand2的数据与Rn的值相加,再加上CPSR中的C条件标志位,结果保存到Rd寄存器,指令格式:
ADC[con][S] Rd,Rn,operand2
D、AND逻辑与操作指令
将寄存器operand2的值与寄存器Rn的值按位作逻辑与操作,结果保存到Rd中,指令格式:
AND[con][S] Rd,Rn,operand2
ANDS R0,R1,#0x01
AND R0,R1,R2
E、ORR逻辑或操作指令
将寄存器operand2的值与寄存器Rn的值按位作逻辑或操作,结果保存到Rd中,指令格式:
ORR[con][S] Rd,Rn,operand2
ORR R0,R0,#0x0F;将R0的低4位置1
F、EOR逻辑异或操作指令
将寄存器operand2的值与寄存器Rn的值按位作逻辑异或操作,结果保存到Rd中,指令格式:
ERR[con][S] Rd,Rn,operand2
H、BIC位清零操作指令
将寄存器Rn的值与寄存器operand2的值反码按位作逻辑与操作,结果保存到Rd中,指令格式:
BIC[con][S] Rd,Rn,operand2
BIC R1,R1,#0x0F
3、比较指令
A、CMP比较指令
用寄存器Rn的值减去寄存器operand2的值,根据操作的结果更新CPSR中相应的条件标志位,以便后面的指令根据相应的条件标志位判断是否执行,指令格式:
CMP[con] Rn,operand2
B、CMN负数比较指令
CMN[con] Rn,operand2
CMN指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较,同时更新CPSR中条件标志位的值。该指令实际完成操作数1和操作数2相
加,并根据结果更改条件标志位。
指令示例:
CMN R1,R0 ;将寄存器R1的值与寄存器R0的值相加,并根据
结果设置CPSR的标志位
4、乘法指令
A、MUL 32位乘法指令
将Rm与Rs中的值相乘,结果的低32位保存到Rd中,指令格式:
MUL[con][S] Rd,Rm,Rs
MUL R0,R1,R2
B、MLA 32位乘法叠加指令
将Rm与Rs中的值相乘,结果再与Rn相加,低32位保存到Rd中,指令格式:
MLA[con][S] Rd,Rm,Rs,Rn
MLA R0,R1,R2,R3
C、UMULL 64位无符号乘法指令
将Rm与Rs的值作无符号数相乘,结果的低32位保存到RdLo中,高32位保存到RdHi中,指令格式:
UMULL[con][S] RdLo,RdHi,Rm,Rs
UMULL R0,R1,R4,R5;(R1,R0)=R4*R5
D、SMULL 64位有符号乘法指令
将Rm与Rs的值作有符号数相乘,结果的低32位保存到RdLo中,高32位保存到RdHi中,指令格式:
SMULL[con][S] RdLo,RdHi,Rm,Rs
SMULL R0,R1,R4,R5;(R1,R0)=R4*R5
六、ARM跳转指令
1、B跳转指令
跳转到指定的地址执行程序,指令格式:
B[con] label
B hello
B #0x30008000
2、BL带链接的跳转指令
将下一条指令的地址拷贝到R14(LR)链接寄存器中,然后跳转到指定地址运行程序,指令格式:
BL[con] label
BL hello
BL用于子函数的调用
3、BX带状态切换的跳转指令
BX指令的格式为:
BX{条件}目标地址
BX指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。
七、程序状态寄存器访问指令
1、MRS指令
MRS指令的格式为:
MRS{条件} 通用寄存器 程序状态寄存器(CPSR或SPSR)
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下两种情况:
Ⅰ.当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
Ⅱ.当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
指令示例:
MRS R0,CPSR ;传送CPSR的内容到R0
MRS R0,SPSR ;传送
SPSR的内容到R0
2、MSR指令
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中的控制位域
八、ARM协处理器指令
1、CDP指令
CDP指令的格式为:
CDP{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2。
CDP指令用于ARM处理器通知ARM协处理器执行特定的操作,若协处理器不能成功完成特定的操作,则产生未定义指令异常。其中协处理器操作码1和协处理 器操作码2为协处理器将要执行的操作,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM处理器的寄存器和存储器。
指令示例:
CDP P3,2,C12,C10,C3,4 ;该指令完成协处理器P3的初始化
2、LDC指令
LDC指令的格式为:
LDC{条件}{L} 协处理器编码,目的寄存器,[源寄存器]
LDC指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指 令为长读取操作,如用于双精度数据的传输。
指令示例:
LDC P3,C4,[R0] ;将ARM处理器的寄存器R0所指向的存储器中的字数 据传送到协处理器P3的寄存器C4中。
3、STC指令
STC指令的格式为:
STC{条件}{L} 协处理器编码,源寄存器,[目的寄存器]
STC指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指 令为长读取操作,如用于双精度数据的传输。
指令示例:
STC P3,C4,[R0] ;将协处理器P3的寄存器C4中的字数据传送到ARM处理 器的寄存器R0所指向的存储器中。
4、MCR指令
MCR指令的格式为:
MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。
MCR指令用于将ARM处理器寄存器中的数据传送到协处理器寄存器中,若协处理器
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮