IOT(ARM汇编)
ARM
一 ARM及ARM寄存器
ARM架构,曾成为进阶精简指令机器(Advance RISC Machine),是一个32位精简指令集(RISC)处理器架构。
最高有效位 MSB 对应大端
最低有效位 LSB 对应小端
armel : 软件浮点 armhf :硬件浮点
arm64:64位的arm默认是hf的,因此不需要hf
1 ARM基础(⭐)
1.1ARM运行模式
1.2ARM工作状态
ARM状态 :32位,执行字对准的ARM指令。
Thumb状态 :16位,执行半字对准的Thumb指令。
他们可以通过特定代码进行切换。
进入不同的工作方式
1.进入Thumb状态:
(1)我们可以执行BS指令,将我们的一个操作数寄存器的状态(位[0])将其置为1。
(2)在Thumb状态进入异常(所有的异常都是ARM状态,当异常处理返回时自动转换Thumb指令)。
2.进入ARM状态:
(1)我们可以执行BS指令,将我们的一个操作数寄存器的状态(位[0])将其置为0。
(2)进入异常时,将PC放入异常模式链接寄存器中,从异常向量地址开始执行也可进入ARM状态。
1.3ARM工作状态寄存器
1.R0-R7 通用寄存器。
2.R13 R14栈上的寄存器,R14(存放返回地址)–>调用者执行的下一条指令。
3.R15 相当于全局指针。
4.CPSR 设计状态转换,只有在System和user下一样,另外模式都会使用除了其以外的一些其他模式。
如 FIQ ,中断情况下,会产生大量数据,需要保存,所以我们保存到了SPSR_fiq里面,当我们返回到user模式下,SPSR_fiq寄存器里的东西会返回到CPSR,也就是我们的应用模式的计算器,就相当于保护了我们的现场,防止造成错误。
5.除了用户模式User以外都成为特权模式(有特定的功能),user称为普通模式。
1.4Thumb工作状态寄存器
寄存器数量少,大概都一样。
1.5Thumb状态ARM状态寄存器
LR链接寄存器 也就相当于返回地址 。
PC 相当于全局指针。
1.6 ARM使用场景
cpu流水线,把一条指令分为多个处理阶段。
ARM使用三级流水线,加速指令处理速度。
三级流水线分别是:取址(fetch),译码(decode),执行(execute)。PC指向fetch的指令。
二 ARM汇编(⭐)
1.ARM指令集
1.1ARM状态
指令集状态
执行状态
安全状态
调试状态
1.2 数据处理指令
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(即乘8)
MOV PC, R14 : 将寄存器R14的值传送到PC中,返回到调用代码并恢复标志位
MVN指令 取反传送指令
MVN R0,#0 :将立即数0取反传送到寄存器R0中,完成R0=-1 (有符号位取反)
ADD 加法指令
ADD{条件}{S} 目的寄存器 ,操作数1,操作数2
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
ADD R0,R1,E2 : R0=R1+R2
ADD R0,R1,#255 :R0 = R1+255#
ADD R0,R2,R3 ,LSL#1 :R0=R2+(R3<<1)
ADC 带进位的加法指令
ADC{条件}{S} 目的寄存器,操作数1,操作数2
ADC指令用于把两个数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32位大的数的加法,注意不要忘记设置s后缀来更改进位标志。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
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)
SBC带进位的减法指令
SBC{条件}{S} 目的寄存器,操作数1,操作数2
BC指令用于把操作数1减去操作数2,再减去CPSR中的C条件标志位的反码,并将结果存到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进制标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。
SUB R0,R1,R2 :R0=R1-R2-!C,并根据结果设置CPSR的进位标志位
CMP 直接比较指令
CMP{条件} 操作数1,操作数2
CMP指令用于把一个寄存器的内容与另一个寄存器的内容或立即数进行比较,同时更新CPSR中的条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1与操作数2的关系(大,小,相等),例如,当操作数1大于操作数2,则此后的有GT后缀的指令可以执行。
CMP R1,R0 :将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位。
CMP R1 , #100 :将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位。
TST 位测试指令
TST{条件} 操作数1,操作数2
TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数据,而操作数2是一个位掩码,该指令一般用于检测是否设置了特定的位。
TST R1,#%1 :用于测试在寄存器R1中是否设置了最低位(%表示二进制数)
TST R1 ,#0xffe :将寄存器R1的值与立即数0xffe按位与,并根据结果设置CPSR的标志位
1.3逻辑运算指令
AND 逻辑与指令
AND{条件}{S} 目的寄存器,操作数1,操作数2
AND指令是用于两个操作数上进行逻辑与运算,并将结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1的某些位。
AND R0,R0 ,#3 ;该指令保持R0的0,1位,其余位清零。
EOR 逻辑异或指令
EOR{条件}{S} 目的寄存器,操作数1,操作数2
EOR指令是用于两个操作数上进行逻辑异或运算,并将结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于反转操作数1的某些位。
EOR R0,R0 ,#3 ;该指令反转R0的0,1位,其余位保持不变。
1.4 位清零指令
BIC 位清零指令
BIC{条件}{S} 目的寄存器,操作数1,操作数2
BIC指令是用于清除操作数1的某些位,并把结果放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2为32位的掩码,如果在掩码中设置了某一位,则清楚这一位。未设置的掩码位保持不变。
BIC R0,R0 ,#%1011 ;该指令清除R0的0,1,和3,其余的位保持不变。
1.5 转移指令
跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转。
1.直接向程序计数器PC写入跳转地址值。
2.使用专门的跳转指令。
ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令:
B指令
B{条件} 目标地址
B指令是最简单的跳转指令,一旦遇到B指令,ARM处理器将立即跳转到指定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为32位,表示的有效偏移为26位(前后32MB的地址空间)
B Label :程序无条件跳转到Label处执行
CMP R1,#0 :当CPSR寄存器中的z条件码置位时,程序跳转到标号Label处执行
BEQ Label
BL指令
BL{条件} 目标地址
BL是另一个跳转指令,但跳转之前,会在寄存器R14中保存当前PC的内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。
BL Label :当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中
BLX指令
BLX{条件} 目标地址
BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态由ARM切换到Thumb状态,该指令同时将PC的当前所有内容保存到寄存器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。
BX指令
BX{条件} 目标地址
BX指令跳转到指令中所指的目标地址,目标地址处的指令可以是ARM指令,也可以是Thumb指令。
1.6 状态寄存器访问指令
MRS指令
MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。
用处:
A 当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
B 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用指令读出程序状态寄存器的值,然后保存。
MSR指令
MSR{条件} 程序状态寄存器(CPSR或SPSR) _<域> ,操作数
MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可以分为4个域:
位[31:24]为条件标志位域,用f表示;
位[23:16]为状态位域,用s表示;
位[15:8]为扩展位域,用x表示;
位[7:0]为控制位域,用c表示;
1.7 加载/存储指令
ARM微处理器支持加载/存储指令用于寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。
LDR指令
LDR{条件} 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而实现程序流程的跳转。
LDRB指令
LDR{条件}B 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个8位的字数据传送到目的寄存器中,同时将寄存器的高24位清零。该指令通常用于从存储器中读取8位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而实现程序流程的跳转。
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0中,并将R0的高24位清零。
LDRB R0,[R1,#8] ;将存储器地址为R1+8的字节数据读入寄存器R0中,并将R0的高24位清零。
LDRH指令
LDR{条件}H 目的寄存器,<存储器地址>
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而实现程序流程的跳转。
LDRH R0,[R1] ;将存储器地址为R1的半字节数据读入寄存器R0中,并将R0的高16位清零。
LDRH R0,[R1,#8] ;将存储器地址为R1+8的半字节数据读入寄存器R0中,并将R0的高16位清零。
STR指令
STR{条件} 源存储器,<存储器地址>
STR指令用于从源存储器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多变,使用方式可参考指令LDR。
STR R0,[R1],#8 ;将R0的字数据写入以R1为地址的寄存器中,并将新地址R1+8写入R1中。
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。
STRB指令
STR{条件}B 源存储器,<存储器地址>
STR指令用于从源存储器中将一个8位的字数据传送到存储器中。该字节数据为源寄存器中的低8位。
STRB R0,[R1] ;将R0的字数据写入以R1为地址的存储器中。
STRB R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。
STRH指令
STR{条件}H 源存储器,<存储器地址>
STR指令用于从源存储器中将一个16位的半字数据传送到存储器中。该字节数据为源寄存器中的低16位。
STRB R0,[R1] ;将R0的半字数据写入以R1为地址的存储器中。
STRB R0,[R1,#8] ;将R0中的半字数据写入以R1+8为地址的存储器中。
批量数据加载/存储指令
ARM微处理器所支持批量加载/存储指令可以在一篇连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送带多个寄存器,批量数据存储指令则完成相反的操作。常见的加载存储指令如下:
-LDM 批量数据加载指令
-STM 批量数据存储指令
LDM(或STM){条件}{类型} 基址存储器{!},寄存器列表{A}
LDM(或STM)指令
用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为以下几种情况:
IA每次传送后地址加1;
IB每次传送前地址加1;
DA每次传送后地址减1;
DB每次传送前地址减1;
FD满递减堆栈;
ED空递减堆栈;
FA满递增堆栈;
EA空递增堆栈;
{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为RO~R15的任意组合。
{A} 为可选后缀,当指令为LDM且寄存器列表中包含R15 ,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
指令示例:
STMFD R13!,{R0, R4—R12 ,LR} ;将寄存器列表中的寄存器(R0 , R4到R12 ,LR)存入堆栈。
LDMFD R13! , {RO , R4—R12 , PC} ;将堆栈内容恢复到寄存器(R0 , R4到R12 , LR)。
1.8 异常产生指令
SWI指令
SWI指令的格式为:
SWI{条件} 24位的立即数
SWI指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数通过其他通用寄存器传递。
指令示例:
SWI 0x02;该指令调用操作系统编号位02的系统例程。
1.8伪代码
AREA (area)
一个汇编程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段,因此在汇编程序的开头,一般的语句会用到AREA。
语法格式:AREA段名 属性1,属性2,…
AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“I”括起来,如l1_testl。属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:
—CODE属性:用于定义代码段,默认为READONLY。 (readonly)
-DATA属性:用于定义数据段,默认为READWRITE。 (readwrite)
-READONLY属性:指定本段为只读,代码段默认为READONLY。(readonly)
—READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE。 (readwrite)
ALIGN 语法格式 (align)
ALIGN{表达式{,偏移量 }}
ALIGN 伪指令可通过添加填充字节的方式,使当前位置满足一定的对其方式。其中,表达式的值用于指定对齐方式,可能的取值为2的幂,如1、2、4、8、16等。若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为:2的表达式次幂+偏移量。
使用示例:
AREA Init, CODE, READONLY, ALIGN=3;指定后面的指令为8字节对齐。
. . .
:指令序列
… .
END
CODE16, CODE32
语法格式: CODE16 (或 CODE32 )
CODE16 伪指令通知编译器,其后的指令序列为 16 位的 Thumb 指令。
CODE32 伪指令通知编译器,其后的指令序列为 32 位的 ARM 指令。
若在汇编源程序中同时包含 ARM 指令和 Thumb 指令时,可用 CODE16 伪指令通知编译器其后的指令序列为 16 位的 Thumb 指令,CODE32 伪指令通知编译器其后的指令序列为 32 位的 ARM 指令。因此,在使用 ARM 指令和 Thumb 指令混合编程的代码里,可用这两条伪指令进行切换,但注意他们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。
ENTRY语法格式:ENTRY
ENTRY 伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个 ENTRY (也可以有多个,当有多个 ENTRY 时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个 ENTRY
使用示例:
AREA Init , CODE , READONLY
ENTRY ;指定应用程序的入口点
…
END
语法格式:END
END 伪指令用于通知编译器已经到了源程序的结尾。
使用示例:
AREA Init , CODE , READONLY
…
END ;指定应用程序的结尾
2.ARM环境搭建
● 操作系统: Ubuntu x64 TLS + Windows 7
● ARM IDE: Keil uVersion ( Eclipse IDE for C/C++ + ARM}{+
/ ADS’/realview等)
● 交叉编译: arm-linux-gnueabi*
● 模拟环境: qemu
3.ARM实战
使用keil
下载链接:
https://blog.csdn.net/get_p_c_j/article/details/140348703?fromshare=blogdetail&sharetype=blogdetail&sharerId=140348703&sharerefer=PC&sharesource=ggyf001&sharefrom=from_link
(本人是一个刚开始学习iot的小白,学习过程中学到的知识,做的一些笔记,分享出来希望能得到各位大佬们的指点,一起进步!加油喔,嘻嘻😁)
作者:m0_73720466