lv9-ARM体系结构与接口技术(5-10) ARM指令

目录

前言

 1.导学-汇编的本质

1.1 指令 伪指令 伪操作

 2.数据处理指令

 2.1MOV指令

2.2机器码和汇编指令一一对应

 2.3立即数

2.3.1伪指令

 2.4加法/减法等常用指令

2.4.1数据运算指令对条件位的影响

3.跳转与存储器访问指令

3.1跳转指令

3.2ARM指令条件码

3.2.1 CMP指令

练习:

3.3内存访问指令

3.3.1load/store指令

 3.4ARM寻址方式

练习:1-100求和

 4.栈的种类和应用

4.1多寄存器内存访问指令

 4.2多寄存器内存访问指令

 4.3栈的种类和应用

 4.3.1栈的概念

4.3.2栈的分类

 4.4栈的应用举例

 5.专用指令

5.1状态寄存器传输指令

5.2软中断指令

5.3协处理器指令

5.4伪指令

6.伪操作与混合编程

6.1伪操作

6.2C和汇编的混合编程

6.3ATPCS协议

总结



前言


 1.导学-汇编的本质

 汇编
    > 每条汇编都会唯一对应一条机器码,且CPU能直接识别和执行
      即汇编中所有的指令都是CPU能够识别和执行的
    > 汇编中寄存器的使用、栈的分配与使用、程序的调用、参数的传递等
      都需要自己维护
 C语言
    > 每条C语句都要被编译器编译成若干条汇编指令才能被CPU识别和执行
      即C语句中的指令CPU不一定能直接识别,需要编译器进行“翻译”
    > C中寄存器的使用、栈的分配与使用、程序的调用、参数的传递等
      都是编译器来分配和维护

1.1 指令 伪指令 伪操作

.global_ start  @声明_ start为全局符号
start : @汇编程序的入口


@ 1.指令:能够编译生成一条32bit机器码, 并且能被CPU识别和执行
        @ 1.数据处理指令:进行数学运算、逻辑运算
        @ 2.跳转指令:实现程序的跳转,本质就是修改了PC寄存器
        @ 3.Load/Srore指令: 访问(读写)内存
        @ 4.状态寄存器传送指令:用于访问(读写) CPSR寄存器
        @ 5.软中断指令:触发软中断
        @ 6.协处理器指令:操作协处理器的指令
@2.伪指令:本身不是指令,编译器可以将其替换成若千条指令
@3.伪操作:不会生成指令,只是在编译阶段告诉编译器怎么编译


MOV R1, #1  @汇编程序
stop:  @死循环,防止程序跑飞
B stop
. end  @汇编程序的结束

 2.数据处理指令

 2.1MOV指令

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口

MOV R1,#1 @MOV数据搬移指令
MOV R1,#1 
MOV R1,#2
MOV R2,#2
MOV R3,#3
@ MOV R3,R2 @ R2的值给R3
@ MOV PC,#0 @PC指向首地址,在这里类似于循环,如果不是4的整数倍,则自动调整为小于该数的最大的4的倍数如 7->4
MVN R1, #0xFF @ R1 =~0XFF MVN按位取反操作

stop: @死循环,防止程序跑飞
	B stop

.end @汇编结束

2.2机器码和汇编指令一一对应

MOV R1,#1 @MOV数据搬移指令
MOV R1,#1 
MOV R1,#2
MOV R2,#2

 2.3立即数

立即数本质是包含在指令里面的数据,是指令的一部分。

优点:取值的时候直接读取到CPU,无需到内存再次读取。速度快,节省空间。

缺点:不能任意用32位的数

MOV R3,#0x12345678 @错误,放不下去
MOV R3,#0x12 


2.3.1伪指令

下面的指令 mov指令转成了MVN,所以也能算

MOV R1,#0xFFFFFFFF

 2.4加法/减法等常用指令

数据运算格式:

《操作码》《目标寄存器》《第一操作寄存器》《第二操作数》

@操作码:表示执行哪一种操作

@目标寄存器:用于存储运算的结果

@第一操作寄存器:存储第一个参与运算的数据

@第二操作数:第二个参与运算的数据(也可是寄存器上的立即数)

 注意:减法不同于加法指令,减法存在被减的关系,如果是数 - 寄存器,则不满足运算格式。

所以,这里补充了逆向减法指令。

MOV R2,#1
MOV R3,#2
ADD R1 ,R2, R3 @R1 = R2 + R3
ADD R1 ,R2, #5 @R1 = R2 + 5
@加法
ADD R1 ,R2 ,#5
ADD R1 ,#5 ,R2@错误格式
@减法
SUB R1  ,R2 ,#5 @R1 = R2 - 5
@逆向减法
RSB R1 ,R2 ,#8  @R1 = 8 - R2

@乘法
MUL R1,R2,R3 @R1 = R2 * R3

@按位与
AND R1,R2,R3
@按位或
ORR R1,R2,R3
@按位异或

EOR R1,R2,R3
@左移
LSL R1,R2,R3 @R1 = R2 << R3
@右移
LSR R1,R2,R3

@位清零
MOV R2,#0XFF
BIC R1,R2,#0X0F @第二操作数的哪一位为1就将第一操作寄存器哪一位清零,结果放入目标寄存器

@数据运算指令的格式扩展
MOV R1,R2,LSL #1 @R2左移一位,数据保存到R1

2.4.1数据运算指令对条件位的影响

注意 指令后面+s是为了查看CPSR寄存器

@数据运算指令对条件位的影响
MOV R2,#2
@SUBS R1,R2,#5 @N置1
@SUBS R1,R2,#2 @Z置1 C置1(借位)
@MOV R2,#0X6FFFFFFF
@ADDS R1,R2,#3 @C置1(进位)
MOV R2,#0X7FFFFFFE
ADDS R1,R2,#3 @V置1(符号位进位 置1)

64位数的运算:

加法

@64位数的运算,分成两个32位的数,低位R1,R3高位R2,R4
MOV R1,#0x00000001
MOV R2,#0x00000002
MOV R3,#0x00000005
MOV R4,#0x00000001
ADDS R5,R1,R3
ADC R6,R2,R4  @本质是 R6 = R2 + R4 + 'C' 考虑了进位,低位若进位C=1

减法

@64位数的运算,分成两个32位的数,低位R1,R3高位R2,R4
MOV R1,#0x00000001
MOV R2,#0x00000002
MOV R3,#0x00000005
MOV R4,#0x00000001

SUBS R5,R1,R3
SBS R6,R2,R4 @本质是 R6 = R2 - R4 - '!C' 考虑借位 C取反,原因查看SPSR图

C语言直接编译成汇编,debug时可查看汇编指令。从汇编的角度看C编程/2的操作,如:可以用位移代替,能用整形就用整形

3.跳转与存储器访问指令

3.1跳转指令

MAIN:
	MOV R1,#1
	MOV R2,#2
	MOV R3,#3
	BL FUNC  @B位不返回跳转指令 BL是返回跳转指令(BL修改了CPSR的LP的值)
	MOV R3,#33
FUNC:
	MOV R4,#2
	MOV R5,#3
	MOV PC,LR @LR值给PC 跳转回主函数

3.2ARM指令条件码

 类似于条件判断

相关标志位:

V Bit[28]
    > 当运算器中进行加法运算且产生符号位进位时该位自动置1,否则为0
    > 当运算器中进行减法运算且产生符号位借位时该位自动置0,否则为1
 CBit[29]
    > 当运算器中进行加法运算且产生进位时该位自动置1,否则为0
    > 当运算器中进行减法运算且产生借位时该位自动置0,否则为1
 Z Bit[30]
    当运算器中产生了0的结果该位自动置1,否则为0
 NBit[31]
    当运算器中产生了负数的结果该位自动置1,否则为0
————————————————

3.2.1 CMP指令

cmp指令相当于R1 -R2,就是做减法然后判断,有以下6个情况:

==        z = 1;

!=         z = 0;

<          C = 0

<=        C = 1 或  z = 1;

>         C = 1 且  z = 0;

>=        C = 1;

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ ARM指令条件码
MAIN:
	MOV R1,#1
	MOV R2,#1
	CMP R1,R2
	BEQ FUNC @if(R1 == R2){B FUNC}
	MOV R3,#3
FUNC:

	MOV R4,#4
	MOV PC,LR

stop: @死循环,防止程序跑飞
	B stop
.end @汇编结束

练习:

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ ARM指令条件码

	MOV R1,#9
	MOV R2,#15

START:
	CMP R1,R2
	@下面三条指令就是条件判断
	BEQ STOP 
	SUBLT R2,R2,R1
	SUBGT R1,R1,R2
	
	B START
	
STOP: @死循环,防止程序跑飞
	B STOP
.end @汇编结束

3.3内存访问指令

3.3.1load/store指令

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ ARM指令条件码

	MOV R1,#0xFF000000
	MOV R2,#0X40000000
	@ 写内存
	@ 将R1寄存器中的数据存储到R2指向的空间
	STR R1,[R2] @保存4个字节到内存word
		STRB R1,[R2] @保存一个字节到内存Byte
		STRH R1,[R2] @保存2个字节到内存HarfWord
	
	@读内存
	@将内存中R2指向的内存空间中的数据读取到R3寄存器
	LDR R3,[R2] @后缀同上
    @LDR R3, =0X10000000 @这个也可以
	
STOP: @死循环,防止程序跑飞
	@B STOP
.end @汇编结束

 3.4ARM寻址方式

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ **********寻址方式**********
	@1.立即寻址
	MOV R1,#1
	ADD R2,R1,#2
	@2.寄存器寻址
	ADD R2,R1,R3
	@3.寄存器移位寻址
	MOV R1,R2,LSL #1
	@4.寄存器间接寻址
	STR R1,[R2]
	@等......
	
	@基址 + 变址寻址
	MOV R1, #0XFFFFFFFF
	MOV R2, #0X40000000
	MOV R3, #4
	STR R1,[R2,R3] @将R1的值写入R2+R3所指向的内存空间
	STR R1,[R2,R3,LSL #1] @将R1的值写入R2+R3<<1 所指向的内存空间
	
	@基址 + 变址寻址的索引方式
	@前索引
	@ MOV R1, #0XFFFFFFFF
	@ MOV R2, #0X40000000
	@ STR R1,[R2,#8] @将R1的值写入R2+8所指向的内存空间
	
	
	@后索引
	@ MOV R1, #0XFFFFFFFF
	@ MOV R2, #0X40000000
	@ STR R1,[R2],#8 @将R1的值写入R2所指向的内存空间 然后R2+8
	
	
	@自动索引
	MOV R1, #0XFFFFFFFF
	MOV R2, #0X40000000
	STR R1,[R2,#8]! @将R1的值写入R2+8所指向的内存空间 然后R2+8
	
	
	
STOP: @死循环,防止程序跑飞
	@B STOP
.end @汇编结束

练习:1-100求和

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ **********100以内正整数求和**********
MOV R2,#0
MOV R3,#1
MOV R4,#101
START:
	CMP R3,R4
	BEQ STOP
	ADDLT R2,R2,R3
	ADD R3,R3,#1
	B START
	
STOP: @死循环,防止程序跑飞

.end @汇编结束

 4.栈的种类和应用

4.1多寄存器内存访问指令

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ **********多寄存器内存访问**********
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R11,#0X40000020
@将R1-R4寄存器的数据保存到内存以R11为起始地址的内存中
@STM R11,{R1-R4}
@将内存中以R11为起始位置的数据读取到R1-R4
 LDM R11,{R1-R4}

@非连续的用,
@顺序打乱  内存依然是从小寄存器到大寄存器保存
STM R11,{R4,R2,R3,R1} 
@自动索引同样适合多寄存器R11最后是0x40000030,四个寄存器一共16字节
STM R11!,{R4,R2,R3,R1} 


STOP: @死循环,防止程序跑飞
	B STOP
.end @汇编结束

 4.2多寄存器内存访问指令

MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R11,#0X40000020
@STMIA R11!,{R1-R4} @STM默认是STMIA  increase after
@STMIB R11!,{R1-R4}
@STMDA R11!,{R1-R4}
STMDB R11!,{R1-R4}

 4.3栈的种类和应用

 4.3.1栈的概念

    栈的本质就是一段内存,程序运行时用于保存一些临时数据
    如局部变量、函数的参数、返回值、以及程序跳转时需要保护的寄存器等

4.3.2栈的分类

  栈的分类
    增栈:压栈时栈指针越来越大,出栈时栈指针越来越小
    减栈:压栈时栈指针越来越大,出栈时栈指针越来越小
    满栈:栈指针指向最后一次压入到栈中的数据,压栈时
       需要先移动栈指针到相邻位置然后再压栈
    空栈:栈指针指向最后一次压入到栈中的数据的相邻位
       置,压栈时可直接压栈,之后需要将栈指针移动
       到相邻位置

 栈分为空增(EA)、空减(ED)、满增(FA)、满减(FD)四种
 ARM处理器一般使用满减栈

代码案例:用FD后缀代替前面的STMID,LDMIA效果一样

.text
.global _start 
_start: 

MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R11,#0X40000020

@STMDB R11!,{R1-R4}
@LDMIA R11!,{R5-R8}

STMFD R11!,{R1-R4}
LDMFD R11!,{R5-R8}

STOP: @死循环,防止程序跑飞
	B STOP
.end 

 4.4栈的应用举例

充分理解C语言里的局部变量!!!

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ **********栈的应用**********
@体会C语言中的局部变量
MOV SP ,#0X40000020 @定义栈指针
MAIN:
	MOV R1,#1
	MOV R2,#3
	BL FUNC
	ADD R3,R1,R2
	B STOP
	
FUNC: @非叶子函数--这里LR需要压栈,因为会被后面的子函数覆盖
	STMFD SP!,{R1,R2,LR} @压栈保护现场
	MOV R1,#10
	MOV R2,#30
	BL FUNC2
	SUB R3,R2,R1
	@读栈(栈中的数据没有清零,所以局部变量需要定义具体的值,不然会读到之前的数)
	LDMFD SP!,{R1,R2,LR} @出栈恢复现场
	MOV PC,LR

FUNC2: @叶子函数
	STMFD SP!,{R1,R2} @压栈 --叶子函数无需保护链接寄存器LR
	MOV R1,#16
	MOV R2,#38
	ADD R3,R1,R2
	LDMFD SP!,{R1,R2} @读栈
	MOV PC,LR

STOP: @死循环,防止程序跑飞
	B STOP
.end @汇编结束

 5.专用指令

5.1状态寄存器传输指令

@ **********状态寄存器传送指令:访问(读写)CPSR寄存器**********
@读CPSR
MRS R1,CPSR

@写CPSR
@MSR CPSR,#0X10  @USER模式
@USER模式无法转成SVC模式,USER模式权限最低
@MSR CPSR,#0XD3

5.2软中断指令

 理解程序进入异常和退出异常的过程

.text
.global _start @声明_ start为全局符号
_start: @汇编程序的入口
@ **********软中断指令**********
@异常向量表 空出32字节
B MAIN
B .
B SWI_HANDLER
B .
B .
B .
B .
B .
@应用程序
MAIN:
	MOV SP,#0X40000020 @默认是SVC态
	MSR CPSR,#0X10
	MOV R1,#1
	MOV R2,#2
	SWI #1  @SWI指令触发软中断,程序进入SVC模式
	ADD R3,R1,R2
	B STOP
@异常处理程序
SWI_HANDLER:
	STMFD SP!,{R1,R2,LR}
	MOV R1,#10
	MOV R2,#20
	ADD R3,R1,R2
	LDMFD SP!,{R1,R2,PC}^ @LR复制给PC,^用于SRPC复制给CRPC


STOP: @死循环,防止程序跑飞
	B STOP
.end @汇编结束

5.3协处理器指令

@协处理器指令:操控协处理器的指令
@1.协处理器数据运算指令
    CDP
@2.协处理器存储器访问指令
    STC  协处理器数据存储到存储器
    LDC  存储器中的数据存储到协处理器
@3.协处理器寄存器传送指令
    MRC 协处理器中寄存器的数据传送到ARM处理器中的寄存器
    MCR ARM处理器中的寄存器的数据传送到协处理器中寄存器

5.4伪指令

 LDR是很特殊的指令,根据格式不同,可以是指令,也可以是伪指令

@伪指令:本身不是指令,编译器可以将其替换成若干指令
	@空指令
	NOP
	@LDR很特殊,根据格式不同,可以是指令或伪指令
	@指令
	@LDR R1 ,[R2]
	@伪指令
	@可以将任意一个32位数放入寄存器
	LDR R1, =0X12345678 @ R1 = 0X12345678
	@STOP的地址存入R1
	LDR R1, =STOP
	@STOP地址里的内容(就是机器码)存入R1
	LDR R1, STOP

6.伪操作与混合编程

6.1伪操作

@ *********伪操作***********

@伪操作不会生成代码,只是在编译阶段告诉编译器怎么编译
@.GUN伪操作一般都以‘.’ 开头

@symbol声明成全局变量
@.global symbol 

@symbol声明成局部变量
@.local symbol 

@.equ DATA,0XFF  @相当于宏定义
@MOV R1,#DATA

@.macro FUNC
@MOV R1,#1
@MOV R2,#2
@.endm
@FUNC  @调用FUNC就是调用两个MOV语句

@if条件语句
@.if 1
@MOV R1,#1
@MOV R2,#2
@.endif


@.rept 3 @重复3遍
@MOV R1,#1
@MOV R2,#2
@.endr

@.weak symbol @即使用到了未定义的symbol,编译器也不报错
@.weak func @即使用到了未定义的FUNC,编译器也不报错
@B func @用未定义的FUNC 执行NOP操作



@word在当前地址申请一个字的空间并将其初始化
@MOV R1,#1
@.word 0XFFFFFFFF
@MOV R2,#2

@byte在当前地址申请一个字的空间并将其初始化
@MOV R1,#1
@.byte 0X1233
@.align 3 @后续指令从2^3的整数倍位置开始存数据
@MOV R2,#2   

@space在当前地址申请任意字节的空间并将其初始化
@MOV R1,#1
@.space 12, 0X123356
@.align 5 @后续指令从2^5的整数倍位置开始存数据
@MOV R2,#2   

@.arm
@MOV R1,#1
@.thumb

6.2C和汇编的混合编程

c和汇编混合编程的原则:

1.在哪种语言环境下符合哪种语言的语法规则

2.在汇编语言中将C语言中的函数当作标号来处理

3.在C语言中将汇编语言中的标号当作函数来处理

共有三种形式:

1.汇编语言(调用)跳转C语言

2.C语言(调用)跳转汇编语言

3.C语言内联汇编

 汇编

.text
.global _start 
_start: 
@ *********C与汇编混合编程*********
MOV SP ,#40000020
MOV R1,#1
MOV R2,#2

BL func_c @跳到C语言定义的函数
MOV R3,#3
B STOP

.global FUNC_ASM @定义FUNC_ASM为全局标号
FUNC_ASM:
	MOV R4,#4
	MOV R5,#5
		
STOP: @死循环,防止程序跑飞
	B STOP
.end 

 C语言


void func_c(){
int a;
	a++;
	asm
	(
		//里面写汇编语言
	"MOV R6,#6\n"
	"MOV R7,#7\n"
	);
	FUNC_ASM(); //跳转到汇编
	a--;
}

6.3ATPCS协议

协议的主要内容:

1.栈的种类,使用满减栈

2.寄存器的使用

        1. R15(PC)程序计数器,只能用于存储程序的指针,不能做其他用途

        2.R14(LR)链接寄存器,只能用于存储返回的地址,不能做其他用途

        3.R13(SP)栈指针,只能用于存储栈指针,不能做其他用途

        4.R0-R3 当函数的参数少于4个 使用 R0-R3 传参,多出4个的部分用栈传递

                        函数的返回值用R0寄存器传递

        5.其余寄存器主要用于存储局部变量

    16: int f1(int a,int b,int c,int d,int e,int f){ 
    17: return a+b+c+d+e+f+g; 
0x00000000  E0801001  ADD       R1,R0,R1
0x00000004  E0811002  ADD       R1,R1,R2
0x00000008  E0811003  ADD       R1,R1,R3
0x0000000C  E59D2000  LDR       R2,[R13]
0x00000010  E0810002  ADD       R0,R1,R2
0x00000014  E59D2004  LDR       R2,[R13,#0x0004]
0x00000018  E0800002  ADD       R0,R0,R2
0x0000001C  E59F3008  LDR       R3,[PC,#0x0008]
0x00000020  E5933000  LDR       R3,[R3]
    18: } 
    19:  
0x00000024  E0800003  ADD       R0,R0,R3
0x00000028  E12FFF1E  BX        R14
0x0000002C  00008154  ANDEQ     R8,R0,R4,ASR R1
    20: int main(){ 
0x00000030  E1A0C00D  MOV       R12,R13
0x00000034  E92DD800  STMDB     R13!,{R11-R12,R14-PC}
0x00000038  E24CB004  SUB       R11,R12,#0x00000004
0x0000003C  E24DD008  SUB       R13,R13,#0x00000008
    21: g = f1(1,2,3,4,5,6); 
    22:  
0x00000040  E3A03005  MOV       R3,#0x00000005
0x00000044  E58D3000  STR       R3,[R13]
0x00000048  E3A03006  MOV       R3,#0x00000006
0x0000004C  E58D3004  STR       R3,[R13,#0x0004]
0x00000050  E3A00001  MOV       R0,#0x00000001
0x00000054  E3A01002  MOV       R1,#0x00000002
0x00000058  E3A02003  MOV       R2,#0x00000003
0x0000005C  E3A03004  MOV       R3,#0x00000004
0x00000060  EBFFFFE6  BL        f1(0x00000000)
0x00000064  E59F300C  LDR       R3,[PC,#0x000C]
0x00000068  E5830000  STR       R0,[R3]
    23: }


总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值