打印
[应用相关]

ARM汇编指令 总结

[复制链接]
2280|36
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hanzhen654|  楼主 | 2019-4-10 16:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. IMPORTEXPORT
IMPORT ,定义表示这是一个外部变量的标号,不是在本程序定义的
EXPORT ,表示本程序里面用到的变量提供给其他模块调用的。
以上两个在汇编和C语言混合编程的时候用到。

使用特权

评论回复
沙发
hanzhen654|  楼主 | 2019-4-10 16:02 | 只看该作者
2. AREA
语法格式:    
   AREA 段名 属性1 ,属性2 ,……    
   AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如:|1_test|。    
  属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:    
    — CODE 属性:用于定义代码段,默认为READONLY 。    
    — DATA 属性:用于定义数据段,默认为READWRITE 。    
    — READONLY 属性:指定本段为只读,代码段默认为READONLY 。    
    — READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE 。    
    — ALIGN 属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。    
    — COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。 
    一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。    
    使用示例:    
AREA Init ,CODE ,READONLY ;   该伪指令定义了一个代码段,段名为Init ,属性为只读。

使用特权

评论回复
板凳
hanzhen654|  楼主 | 2019-4-10 16:02 | 只看该作者
3. LDR、LDRB、LDRH
ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。常用的加载存储指令如下:
—  LDR     字数据加载指令
— LDRB    字节数据加载指令
—  LDRH    半字数据加载指令

使用特权

评论回复
地板
buffered| | 2019-4-10 16:13 | 只看该作者
感谢分享!学习下。

使用特权

评论回复
5
hanzhen654|  楼主 | 2019-4-10 17:39 | 只看该作者
1)LDR指令有两种用法:
a、ldr加载指令
LDR指令的格式为:
LDR{条件}  目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,丏寻址方式灵活多样,请读者认真掌握。
指令示例:
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×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2  ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
ARM是RISC结构,数据从内存到CPU间的移劢只能通过L/S指令来完成,也就是ldr/str指令。  比如想把数据从内存中某处读取到寄存器中,只能使用ldr 比如: ldr r0, 0x12345678 
就是把0x12345678返个地址中的值存放到r0中。

使用特权

评论回复
6
hanzhen654|  楼主 | 2019-4-10 17:40 | 只看该作者
b、ldr伪指令
ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令。
LDR伪指令的形式是“LDRRn,=expr”。
例子:
COUNT EQU       0x40003100
……
LDR       R1,=COUNT
MOV      R0,#0
STR       R0,[R1]

COUNT是我们定义的一个变量,地址为0x40003100。这种定义方法在汇编语言中是很常见的,如果使用过单片机的话,应该都熟悉这种用法。
LDR       R1,=COUNT是将COUNT这个变量的地址,也就是0x40003100放到R1中。
MOV      R0,#0是将立即数0放到R0中。最后一句STR     R0,[R1]是一个典型的存储指令,将R0中的值放到以R1中的值为地址的存储单元去。实际就是将0放到地址为0x40003100的存储单元中去。

下面还有一个例子,将COUNT的值赋给R0
LDR       R1,=COUNT
LDR       R0,[R1]
LDR       R1,=COUNT这条伪指令,是怎样完成将COUNT的地址赋给R1,有兴趣的可以看它编译后的结果。这条指令实际上会编译成一条LDR指令和一条DCD伪指令。

使用特权

评论回复
7
hanzhen654|  楼主 | 2019-4-10 17:40 | 只看该作者
  LDRB指令
LDRB指令的格式为: LDR{条件}B 目的寄存器,<存储器地址>
LDRB指令用于将存储器中低8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的数据被当作目的地址,从而可以实现程序流程的跳转。
指令示例:
LDRB R0,[R1]         ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8]    ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。

使用特权

评论回复
8
hanzhen654|  楼主 | 2019-4-10 17:41 | 只看该作者
 LDRH指令
LDRH指令的格式为: LDR{条件}H 目的寄存器,<存储器地址>
LDRH指令用于将存储器中低16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
指令示例:
LDRH R0,[R1]   ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,#8]  ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,R2]    ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零。

使用特权

评论回复
9
hanzhen654|  楼主 | 2019-4-10 17:41 | 只看该作者
SUB  减法指令
SUB{条件}{S} , ,  dest = op_1 - op_2
SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 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)
减法可以在有符号和无符号数上进行。
ps: 带进位的减法SBC

使用特权

评论回复
10
hanzhen654|  楼主 | 2019-4-10 17:42 | 只看该作者
CMP 、TST、BNE、BEQ
BNE和BEQ经常与CMP 或TST搭配使用。
在讲解这几个指令前,先介绍下CPSR这个寄存器,因为CMP和TST指令会对CPSR中的某些位产生影响,而BNE和BEQ指令的动作正是与CPSR中被影响的这些位有关。
CMP:
假设现在AX寄存器中的数是0002H,BX寄存器中的数是0003H。执行的指令是:CMP AX, BX
执行这条指令时,先做用AX中的数减去BX中的数的减法运算。列出二进制运算式子:
0000 0000 0000 0010
-0000 0000 0000 0011
_________________________________
(借位1) 1111 1111 1111 1111
所以,运算结果是 0FFFFH 根据这个结果,各标志位将会被分别设置成以下值:
CF=1,因为有借位   // CF即为上述CPSR中的C
OF=0,未溢出           // OF即为上述CPSR中的V
SF=1,结果是负数   // SF即为上述CPSR中的N
ZF=0,结果不全是零    // ZF即为上述CPSR中的Z
还有AF, PF等也会相应地被设置。
CMP 比较指令做了减法运算以后,根据运算结果设置了各个标志位。
标志位设置过以后,0FFFFH这个减法运算的结果就没用了,它被丢弃,不保存。
执行过了CMP指令以后,除了CF,ZF,OF,SF,等各个标志位变化外,其它的数据不变。
对照普通的减法指令 SUB AX, BX,它们的区别就在于:
SUB指令执行过以后,原来AX中的被减数丢了,被换成了减法的结果。
CMP指令执行过以后,被减数、减数都保持原样不变。

使用特权

评论回复
11
hanzhen654|  楼主 | 2019-4-10 17:42 | 只看该作者
TST:
逻辑处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位与运算,并根据运算结果更新CPSR中条件标志位的值。当前运算结果为非0,则Z=0;当前运算结果为0,则Z=1

BNE:数据跳转指令,标志寄存器中Z标志位等于零时,跳转到BNE后标签处。特别要注意这里,通常我们说BNE是“不相等”或“不为零”时跳转,此处的“不相等”或“不为零”是指比较结果不相等或做减法不为零,不是指Z标志位。比较结果不相等或做减法不为零时,Z标志位是等于零的。

BEQ:数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BEQ后标签处。

使用特权

评论回复
12
hanzhen654|  楼主 | 2019-4-10 17:42 | 只看该作者
STR、STRB、STRH指令
— STR     字数据存储指令
— STRB    字节数据存储指令
— STRH    半字数据存储指令

A、STR指令的格式为:STR{条件} 源寄存器,<存储器地址>
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
指令示例:
STR   R0,[R1],#8    ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR   R0,[R1,#8]    ;将R0中的字数据写入以R1+8为地址的存储器中。

使用特权

评论回复
13
hanzhen654|  楼主 | 2019-4-10 17:46 | 只看该作者
B、STRB指令的格式为:STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
指令示例:
STRB R0,[R1]         ;将寄存器R0中的字节数据写入以R1为地址的存储器中。
STRB R0,[R1,#8]    ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。

使用特权

评论回复
14
hanzhen654|  楼主 | 2019-4-10 17:49 | 只看该作者
C、STRH指令的格式为:STR{条件}H 源寄存器,<存储器地址>
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。

指令示例:
STRH R0,[R1]         ;将寄存器R0中的半字数据写入以R1为地址的存储器中。
STRH R0,[R1,#8]    ;将寄存器R0中的半字数据写入以R1+8为地址的存储器中。

使用特权

评论回复
15
hanzhen654|  楼主 | 2019-4-10 18:10 | 只看该作者
跳转指令B、BL、BX、BLX 和 BXJ的区别
跳转指令用于实现程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转:
(1) 使用专门的跳转指令。
(2) 直接向程序计数器 PC 写入跳转地址值。
通过向程序计数器 PC 写入跳转地址值,可以实现在4GB 的地址空间中的任意跳转,在跳转之前结合使用MOV LR , PC等类似指令,可以保存下一条指令地址作为将来的返回地址值,从而实现在 4GB 连续的线性地址空间的子程序调用。
专门的跳转指令:B、BL、BX、BLX 和 BXJ  跳转、带链接跳转(带返回的跳转)、跳转并切换指令集、带链接跳转并切换指令集(带返回的跳转并切换指令集)、跳转并转换到 Jazelle 状态。

使用特权

评论回复
16
hanzhen654|  楼主 | 2019-4-10 18:10 | 只看该作者
 B 指令
B 指令的格式为:B{条件} 目标地址
B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间)。以下指令:B Label ;程序无条件跳转到标号 Label 处执行
CMP R1 ,# 0 ;当 CPSR 寄存器中的 Z 条件码置位时,程序跳转到标号Label 处执行
BEQ Label

使用特权

评论回复
17
hanzhen654|  楼主 | 2019-4-10 18:12 | 只看该作者
 BL 指令
BL 指令的格式为:BL{条件} 目标地址
BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。以下指令:BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中

使用特权

评论回复
18
hanzhen654|  楼主 | 2019-4-10 18:13 | 只看该作者
BLX 指令
BLX 指令的格式为:BLX 目标地址
BLX 指令从ARM 指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM 状态切换到Thumb 状态,该指令同时将PC 的当前内容保存到寄存器R14 中。因此,当子程序使用Thumb 指令集,而调用者使用ARM 指令集时,可以通过BLX 指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14 值复制到PC 中来完成。

使用特权

评论回复
19
hanzhen654|  楼主 | 2019-4-10 18:13 | 只看该作者
BX 指令 
BX 指令的格式为:BX{条件} 目标地址
BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb指令。
语法

op1{cond}{.W}<wbr />label
op2{cond} <wbr />Rm

其中:op1是下列项之一:
B:跳转;BL:带链接跳转;BLX:带链接跳转并切换指令集。
op2是下列项之一:
BX:跳转并切换指令集;BLX:带链接跳转并切换指令集;BXJ:跳转并转换为Jazelle执行。
cond:是一个可选的条件代码。 cond 不能用于此指令的所有形式。
.W:是一个可选的指令宽度说明符,用于强制要求在 Thumb-2 中使用 32 位 B 指令。
label:是一个程序相对的表达式。
Rm:是一个寄存器,包含要跳转到的目标地址。
所有这些指令均会引发跳转,或跳转到 label,或跳转到包含在Rm中的地址处。此外:
BL 和 BLSTMCSIAX 指令可将下一个指令的地址复制到 lr(r14,链接寄存器)中。
BX 和 BLX 指令可将处理器的状态从 ARM 更改为 Thumb,或从 Thumb 更改为 ARM。
BLX label 无论何种情况,始终会更改处理器的状态。
BX Rm 和 BLX Rm 可从 Rm 的位 [0] 推算出目标状态:
如果 Rm 的位 [0] 为 0,则处理器的状态会更改为(或保持在)ARM 状态
如果 Rm 的位 [0] 为 1,则处理器的状态会更改为(或保持在)Thumb 状态。
BXJ 指令会将处理器的状态更改为 Jazelle

使用特权

评论回复
20
hanzhen654|  楼主 | 2019-4-10 18:14 | 只看该作者
STMFD和LDMFD指令
这两条指令分别是入栈和出栈的意思,因此先来讲一下堆栈的相关概念:
a)     满堆栈:即入栈后堆栈指针sp指向最后一个入栈的元素。也就是sp先减一(加一)再入栈。
b)     空堆栈:即入栈后堆栈指针指向最后一个入栈元素的下一个元素。也就是先入栈sp再减一(或加一)。
c)     递增堆栈:即堆栈一开始的地址是低地址,向高地址开始递增。就如同一个水杯(假设上面地址大)开口的是大地址,从杯底开始装水。
d)     递减堆栈:即堆栈一开始的地址是高地址,向低地址开始递增。就如同刚才说的那个水杯,现在开口的是小地址,从大地址开始用。
有这些类型就可以构成4种不同的堆栈方式,arm的栈一般我们用满堆栈、递减堆栈。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

73

主题

1766

帖子

2

粉丝