鸿 网 互 联 www.68idc.cn

ARM汇编指令(ARM寻址方式、汇编指令、伪指令

来源:互联网 作者:佚名 时间:2015-10-09 05:47
1、寻址 方式 所谓寻址 方式 就是:处理器根据 指令 中给出的地址信息来寻找物理地址的方法。 1)立即寻址 立即寻址也叫立即数寻址,这是一种特殊的寻址 方式 ,操作数本身就是在 指令 中给出的。 只要取出 指令 也就是取得了操作数,这个操作数被称为立即数

1、寻址方式

所谓寻址方式就是:处理器根据指令中给出的地址信息来寻找物理地址的方法。

1)立即寻址

立即寻址也叫立即数寻址,这是一种特殊的寻址方式,操作数本身就是在指令中给出的。

只要取出指令也就是取得了操作数,这个操作数被称为立即数,对应的寻址方式也就叫做立即数寻址。

例如:

△:ADD R0,R0,#1        ;R0<-R0+1

△:ADD R0,R0,#0X3F     ;R0<-R0+0X3F

2)寄存器寻址

寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常使用的一种方式

也是一种执行效率较高的寻址方式

例程:

ADD R0,R1,R2       ;R0<-R1+R2

3)寄存器间接寻址

寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身就放在存储器中。

例如:

ADD R0,R1,[R2]     ;R0<-R1+[R2]

LDR R0,[R1]         ;R0<-[R1]

4)基址变址寻址

基址变址寻址就是将寄存器(该寄存器一般称为基址寄存器)的内容与指令中给出的地址偏移量相加,

从而得到一个操作数的有效地址:

例如:

LDR R0,[R1,#4]    ;R0<-[R1+4]

LDR R0,[R1,#4]!     ;R0<-[R1+4]、R1<-R1+4

LDR R0,[R1],#4     ;R0<-[R1+4]、R1<-R1+4

4)多寄存器寻址

采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。

这种寻址方式可以用一条指令完成传送最多16个通用寄存器的值。

例如:

LDMIA R0,{R1,R2,R3,R4}    ;R1<-[R0]

                              ;R2<-[R0+4]

                              ;R3<-[R0+8]

                              ;R4<-[R0+12]

注意:该指令的后缀IA表示在每次执行完加载、存储操作后,R0按字长度增加,因此,指令可以将

连续存储单元的值送到R1~R4。

5)相对寻址

与基址变址寻址方式相类似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,

将两者相加之后得到的操作数的有效地址。

例如:

BL NEX

6)堆栈寻址

T堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称作为

堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。

递增堆栈:向高地址方向生长

递减堆栈:向低地址方向生长

满堆栈:堆栈指针指向最后压入堆栈的有效数据项

空堆栈:堆栈指针指向下一个要放入数据的空位置

2、ARM指令

1)跳转指令

跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:

△:使用专门的跳转指令

△:直接向程序计数器PC写入跳转地址值,通过向程序计数器PC写入跳转地址值,可以实现在4GB的

地址空间中的任意跳转,在跳转之前结合使用MOV LR,PC

等类似的指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。

 

在ARM指令集中的跳转指令可以完成从当前指令向前或者向后的32MB的地址空间的跳转,包括以下四条指令

△:B     跳转指令

△:BL    带返回的跳转至灵

△:BLX   带返回和状态切换的跳转指令

△:BX    带状态切换的跳转指令

①、B指令

B{条件}   目标地址

B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里开始继续执行。

例如:

CMP R1,#0

BEQ LABEL   ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号LABEL处执行

顺便把指令的条件贴出来:

Tiny6410学习ing鈥敚ㄈRM<strong>裸机</strong><strong>开发</strong>鈥敚1)、ARM<strong><strong>汇编</strong></strong><strong><strong>指令</strong></strong>(ARM寻址<strong>方式</strong>、<strong><strong>汇编</strong></strong><strong><strong>指令</strong></strong>、伪<strong><strong>指令</strong></strong>-②

②、BL指令

BL{条件}   目标地址

BL是另一个跳转指令,但跳转之前,会在寄存器R14(LR)中保存PC当前值,

因此,可以通过将LR的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。

指令是实现子程序调用的一个基本但常用的手段。

③、BLX指令

BLX 目标地址

BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM状态切换到Thumb状态,

指令同时将PC的当前内容保存到R14中。

因此,当子程序使用Thumb指令时,而调用者使用ARM指令,可以通过BLX指令实现子程序的调用和处理器

工作状态的切换。

同时,子程序返回可以通过寄存器R14值复制到PC中来完成返回。

④、BX指令

BX{条件} 目标地址

BX指令跳转到指令中指定的目标地址,目标地址的指令既可以是ARM指令,也可以是Thumb指令

2、数据处理指令

数据处理指令可以分为数据传送指令、算术逻辑运算指令和比较指令等。

数据传送指令用于在寄存器和寄存器之间(这里一定要看清楚是寄存器与寄存器!!!)进行数据的双向传输。

算术逻辑运算指令完成常用的算术和逻辑的运算,该指令不但将运算结果博爱存在目的寄存器中,同时更新CPSR中的相应条件标志位。

1)MOV指令

MOC{条件}{S}   目的寄存器,原操作数(都是寄存器!!!)

MOV指令完成从一个寄存器、被移位的寄存器加载到目的寄存器。

其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

例程:

MOV R1,R0  

MOV PC,R14

MOV R1,R0,LSL #3

2)MVN指令

MVN{条件}{S}   目的寄存器,原操作数

MVN指令完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。

与MOV指令不同之处是在传送之前按位取反了,既把一个取反的值传送给目的寄存器中。

其中S决定指令的操作是否影响CPSR中条件标识为的值,当没有S时指令不更新CPSR中条件标志位的值。

例程:

MVN R0,#0XFF

3)CMP指令

CMP{条件} 操作数1,操作数2

CMP指令用于把一个寄存器内容和另一个寄存器的内容或者立即数进行比较,同时更新CPSR中

条件标志位的值。

指令进行一次减法运算,但是不保存结果,只更改条件标志位(其中指令条件上边的图片~~)~~

例如:

CMP R1,RO

CMP R1,#100   ;将寄存器R1中的值与立即数100相减,并根据结果设置CPSR的标志位

4)TST指令

TST{条件}   操作数1,操作数2

TST指令用于把一个寄存器的内容和另一个寄存器的内容或者立即数按位的与运算。

并根据结果更新CPSR中条件标志位的值。

操作数1是要测试的数据,而操作数2是一个位掩码,根据测试结果设置相应的标志位。

例程:

TST R1,#%1   ;用于测试在寄存器R1中是否设置了最低位(%表示二进制数)。

5)ADD指令

ADD{条件}{S} 目的寄存器,操作数1,操作数2

ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。

操作数1一概是一个寄存器,操作数2可以是一个寄存器,被一位的寄存器,或者一个立即数。

例程:

ADD R0,R1,R2

ADD R0,R2,R3,LSL#1

6)SUB指令

不想说~~因为跟ADD指令一模一样,只是一个加一个减~~

7)AND指令

AND{条件}{S} 目的寄存器,操作数1,操作数2

AND指令用于在两个操作数上进行逻辑与运算,并肩结果放置在目的寄存器。

格式跟ADD一样。

例程:

AND R0,R0,#3      ;该指令保持R0的0、1位,其余位清零

8)ORR指令

按位或,格式跟AND指令一样~~

功能:常用于设置操作数1的某些位。

9)BIC指令

BIC{条件}{S} Rd,Rn,operand2

BIC指令用于清除Rn中的某些位,并把结果存放在Rd中,操作数operand2为32位的掩码,如果

掩码中设置了某一位为1,则清除这一位。

例程:

BIC R0,R0,#11   ;将R0的0,1,3位清零,其余位不变。

10)MUL指令

MUL{条件}{S}   目的寄存器,操作数1,操作数2

其中操作数1和操作数2均为32位的有符号数或者无符号数。

11)MRS指令程序状态寄存器访问指令

MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)

MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。

注意:

指令用于一下情况:

a、当需要改变程序状态寄存器时,可以用MRS将程序状态寄存器的内容读入通用寄存器,

修改后再写回程序状态寄存器。

b、当在异常处理或进程切换时,需要保存程序状态寄存器的值,可以先用该指令读出程序状态寄存器的值,然后保存。

12)MSR指令(与MRS相对应)

MSR{条件} 程序转台寄存器(CPSR或者SPSR)_<域>,操作数

MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中,其中,操作数可以为通用寄存器或立即数。

<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域:

位[31:24]为条件标志位域,用f表示

位[23:16]为状态位域,用s表示

位[15:8]为扩展为域,用x表示

位[7:0]为控制位域,用c表示

指令通常用于回复或者改变程序转台寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。

例程:

MSR CPSR_C,RO   ;传送R0的内容到SPSR,但是仅仅修改CPSR中的位控制域

13)LDR指令(加载指令

首先介绍一下加载/存储指令

ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。

LDR{条件} 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的数据传送到目的寄存器中。

指令通常用于从存储器中读取32位的子数据到通用寄存器,然后对数据进行处理。

14)LDRB指令

格式通LDR指令一样!

LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。

15)LDRH指令

LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器中的高16位清零。

16)STR指令(存储指令

STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。

17)批量加载/存储指令-LDM/STM

ARM微处理器所支持的批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,

批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。

LDM{条件}{类型} 基址寄存器{!},寄存器列表

LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间

传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。

类型:

IA:每次传送后地址加1

IB:每次传送前地址加1

DA:每次传送后地址减1

DB:每次传送前地址减1

FD:满递减堆栈

ED:空递减堆栈

FA:满递增堆栈

EA:空递增堆栈

{!}:

为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。

{^}:

为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据缠讼之外,还将SPSR复制到CPSR。

例程:

STM R13!,{R0,R4-R12,LR}   ;将寄存器列表中的寄存器(R0,R4-R12,R13)存入堆栈

LDMFD R13!,{R0,R4-R12,PC}   ;将堆栈内容恢复到寄存器(R0,R4-R12,LR)

18)SWP指令

SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]

SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的子数据传送到源寄存器2所指向的存储器中。

显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。

例程:

SWP R0,R0,[R1]

19)移位指令

ARM微处理器所支持数据的移位操作~~

移位操作在ARM指令集中不作为单独的指令使用,他只能作为指令格式中是一个字段,在汇编语言中表示为指令中的选项。

移位操作包括如下6中:ASL和LSL是等价的!

△:LSL   逻辑左移(按操作数所指定的数据向左移位,低位用0来补。其中,操作数可以是通用寄存器或者立即数(0~31)。)
△:ASL   算术左移
△:LSR   逻辑右移
△:ASR   算术右移
△:ROR   循环右移(注意:操作数可以是通用寄存器,也可以是立即数(0~31)。)
20)异常产生指令(暂时用不到~~所以不写了~~)
ARM微处理器所支持的异常指令有两条:
SWI   软件中断指令
BKPT  断点中断指令
3、ARM伪指令
在ARM汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有
相对应的操作码,通常称这些特殊指令助记符为伪指令,他们所完成的操作称为伪操作。
伪操作在源程序中的作用是为了完成汇编程序做各种准备工作的,这些伪指令仅在汇编过程中起作用,一旦
汇编结束,伪指令的是名也就完成了。
在ARM的汇编程序中,有如下几种伪指令
符号定义伪指令、数据定义伪指令汇编控制伪指令、宏指令以及其他伪指令
1)符号定义伪指令
符号定义伪指令用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等操作。
常见的有:
△:定义全局变量的GBLA、GBLL和GBLS
△:定义局部变量的LCAL、LCLL和LCLS
△:对变量赋值的SETA、SETL、SETS
△:为通用寄存器列表定义名称的RLIST
 
 
①、GBLA/GBLL/GBLS
格式:
GBLA/GBLL/GBLS   全局变量名(在整个程序范围内变量名必须唯一!!)
用于定义一个ARM程序中的全局变量,并将其初始化。
△:GBLA:定义一个全局的数字变量,并初始化为0;
△:GBLL:定义一个全局的逻辑变量,并初始化为F(假);
△:GBLS:定义一个全局的字符串变量,并初始化为空;

例程:

GBLA TEST

TEST SETA 0XAA

②、LCALL/LCLL/LCLS

跟①是一样一样的~~只不过是局部变量而已!

③RLIST

格式:

名称 RLIST {寄存器列表}

RLIST伪指令用于对一个通用寄存器列表定义名称,使用该伪指令定义的列表名称可在ARM指令LDM/STM中使用。

在LDM/STM指令中,列表中的寄存器访问次序为根据寄存器的标号由低到高,而与列表中的寄存器排列次序无关。

例程:

REGLIST RLIST {R0-R5,R8,R10}   ;将寄存器列表名称定义为REGLIST,可以在ARM指令LDM/STM中通过该名称访问寄存器列表。

2)数据定义伪指令

数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。

常见的数据定义伪指令有:

DCB   DCW   DCD   DCFD

DCDS  DCQ   SPACE MAP   FIELD

 

 

①、DCB指令

格式:

标号 DCB 表达式

DCB伪指令用于分配一个连续的自己存储单元并用伪指令中指定的表达式初始化。

其中,表达式可以为0~255的数字或字符串。

DCB也可以用”=“代替。

例程:

STR DCB "This is a test!"   ;分配一片连续的字节存储单元并初始化

②、SPACE指令

格式:

标号 SPACE 表达式

SPACE伪指令用于分配一片连续的存储区域并初始化为0。

其中,表达式为要分配的字节数。SPACE可以用”%“代替。

例程:

DATASPACE SPACE 100   ;分配连续的100字节的存储单元并初始化为0

③、MAP指令

格式:

MAP 表达式{,基址寄存器}

MAP为指令用于定义一个结构化的内存表的首地址。

MAP也可以用”^“代替。

表达式可以为程序中的标号或数学表达式,基址寄存器为可选项,当基址寄存器选择不存在时,

表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。

MAP伪指令通常与FIELD伪指令配合使用来定义结构化的内存表。

例程:

MAP 0x100,R0    ;定义结构化内存表首地址的值为0x100+R0

④FILED指令

通常都与MAP指令一起用。

格式:

标号 FIELD 表达式

FIELD为指令用于定义一个结构化内存表中的数据域,FILED也可用”#“代替。

表达式的值为当前数据域在内存表中所占的字节数。

 

FIELD伪指令定义内存表中的各个数据域,并可以为每个数据域指定一个标号使其他的指令

引用。

例程:

MAP 0X100   ;定义结构化内存表首地址为0x100

A FIELD 16  ;定义A的长度为16个字节,位置位0x100

B FIELD 32  ;定义B的长度诶32个字节,位置位0x110

3)汇编控制伪指令(这个东西不想写了,用到了,一查就哦了~~写多了也没用多了好)

汇编控制伪指令用于控制汇编陈旭的执行流程,常用的汇编控制伪指令包括以下几条:

△:IF、ELSE、ENDIF

△:WHILE、WEND

△:MACRO、WEND

△:MEXIT

4)其它伪指令

△:AREA

△:ALIGN

△:CODE16、CODE32

△:ENTRY

△:END

△:EQU

△:EXPORT(Or GLOBAL)(这个是声明一个u且安居的标号,该标号可在其它文件引用!!和C语言一个道理~~)

△:IMPORT

△:EXTERN

△:GET(Or INCLUDE)

 

 

这里我就说下IPMORT指令吧:

IPMORT 标号

IMPORT伪指令用于通知编译器要使用得标号在其他的源文件中定义,但要在当前源文件中引用。

标号在程序中区分大小写。

使用实例:

ARET Init,CODE,READONLY

IMPORT Main   ;通知编译器当前文件要引用标号Main,但Main在其它的源文件中定义的!

网友评论
<