【ARM硬件】ARM汇编指令

本文详细介绍了汇编语言的基本指令集,包括数据处理、特殊寄存器操作、内存及栈操作等,并解释了不同类型的指令如何应用于具体的计算任务中。
汇编指令:机器码的助记符

数据处理指令
特殊寄存器操作指令
内存操作指令
栈操作指令
协处理器操作指令(协助主处理器操作)

汇编语言中中操作数有三种:寄存器操作数、存储器操作数和立即数。
其中立即数相当于高级语言中的常量(常数),它是直接出现在指令中的数,不用存储在寄存器或存储器中的数,如指令ADD AL,06H中的06H即为立即数。

改寄存器里面的值只能是汇编语言。
Linux系统将c程序转换为汇编语言:arm-linux-gcc -S add.c -o add.s
vim add.s
数据传输指令:
mov  传输指令
	mov{S}<c> <Rd>, #<const>   传递立即数const到目标寄存器
	{S}  表示movs,有s的时候才可以更改NZCV标志位
	<c> 指令可以条件执行
	<Rd>  目标寄存器
	#<const>  操作数,(必须是立即数)#1
	mov r0, #1

mvn 取反传输
mvn r0, #12   ==== r0 = ~12
mvn r0, r1    ==== r0 = ~r1

算数逻辑运算指令:
目标寄存器和操作数是同一个寄存器时,可以省略
add
		ADD{S}<c> <Rd>, <Rn>, #<const>
		add r0, r1, #12  ==== r0=r1+12
		add r0, r1, r2   ==== r0=r1+r2
		add r0, #12     ==== r0 = r0+12
		add r0, r1       ==== r0 = r0+r1
sub  减法
		SUB{S}<c> <Rd>, <Rn>, #<const>
		sub  r0, r1, #12 ==== r0 = r1-12
		sub  r0, r1, r2  ==== r0 = r1-r2
		sub  r0, #12     ==== r0 = r0-12
		sub  r0, r1       ==== r0 = r0-r1
mul  乘法
		mul{S}<c> <Rd>, <Rn>, <Rm>
		mul  r0, r1, r2  ==== r0 = r1*r2
rsb 反向减
		RSB{S}<c> <Rd>, <Rn>, #<const>
		rsb  r0, r1, #12 ==== r0 = 12-r1
		rsb  r0, r1, r2  ==== r0 = r2-r1
		rsb  r0, #12     ==== r0 = 12-r0
		rsb  r0, r1      ==== r0 = r1-r0
adc  带进位的加法
		ADC{S}<c> <Rd>, <Rn>, #<const>
		adc r0, r1, #12  ==== r0 = r1+12+C(NZCV标志) 完成64位加法的高位运算
sbc  带借位的减法
		SBC{S}<c> <Rd>, <Rn>, #<const>
		sbc r0, r1, #12  ==== r0 = r1-12-!C(NZCV标志) 完成64位减法的高位运算

int i;
	 i = i|1<<9;  置位
	 i = i&~(1<<9) 清除
位操作指令:
and   按位与
		AND{S}<c> <Rd>, <Rn>, #<const> 
		and r0, r1, #12   ==== r0=r1&#12
orr   按位或
		ORR{S}<c> <Rd>, <Rn>, #<const>
		orr r0, r1, #12   ==== r0=r1|12
eor   按位异或
		EOR{S}<c> <Rd>, <Rn>, #<const>
		eor r0, r1, #12   ==== r0=r1^12
bic   位清除,  清除第一操作数,第二操作数为1的那些位(取反再与)
		BIC{S}<c> <Rd>, <Rn>, #<const>
		bic r0, r1, #1   ==== r0 = r1 & ~(1)
		bic r0, #(1<<15)
移位操作指令:
lsl 逻辑左移 ,高位丢失,低位补0
		LSL{S}<c> <Rd>, <Rn>, <Rm>
		lsl r0, r1, r2  ==== r0 = r1<<r2
		lsl r0, r1, #1  ==== r0 = r1<<1	
lsr 逻辑右移 ,低位丢失,高位补0
	LSR{S}<c> <Rd>, <Rn>, <Rm>
		lsr r0, r1, r2  ==== r0 = r1>>r2
		lsr r0, r1, #1  ==== r0 = r1>>1
ror 循环右移
asr 算数右移, 符号位不变,移位操作按照逻辑右移,空位补符号
	ASR{S}<c> <Rd>, <Rn>, <Rm>

条件判断执行:
	eq    =
	ne   !=
	lt     <
	le    <=
	gt    >
	ge    >=
	
	moveq  r0, #12  条件执行,当Z==1	时,指令执行
	MVN{S}{<c>}{<q>} <Rd>, <Rm>, <type> <Rs>
	<type>表示移位
	表示指令支持移位操作
	先将<Rm> 移位操作后执行mvn
	
	ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}  表示指令可以增加移位
	
cmp   比较, 适合所有条件 
		cmp r1, #3  ====  根据r1-3的结果修改NZCV
		cmp r1, r2  ====  根据r1-r2的结果修改NZCV
cmn  cmp的扩展,快速判断两个数是否相反数
		cmn r1, #3  ====  根据r1+3的结果修改NZCV
		cmn r1, r2  ====  根据r1+r2的结果修改NZCV
teq  判断相等,只能和NE或EQ使用
	TEQ<c> <Rn>, #<const>
		teq r0, #12====  根据r1^12的结果修改NZCV
		teq r1, r0  ====  根据r1^r2的结果修改NZCV

tst  位测试, 判断第一操作数,第二操作数为1的那些位是0还是1
	  可以使用的条件 ne和eq
	TST<c> <Rn>, #<const>
	tst r0, #1  ==== 根据r1&1的结果修改NZCV,判断r0的最后一位是否为0
		tst  r0, #0xf ====判断r0最后四位是否都为0
伪指令:
ldr  可以传递任意32位数据到指定寄存器
ldr r0, =0x12345678 ====  r0 = 0x12345678

跳转指令:
相对跳转:基于当前PC前后32M范围寻找标号
标号:地址助记符(只表示地址,不占空间)
b   label		跳转到标号处执行代码,不关心返回不返回
bl  label		跳转到标号处执行代码,保存返回地址到lr
绝对跳转:对pc进行写操作
mov pc, #12
ldr pc, =0x12345678
ldr pc, =label;将标号表示的地址给目标寄存器
用汇编写出for(i = 0;i < 5,i++)

功能寄存器操作指令:
msr cpsr,r0   cpsr = r0
mrs r0,cpsr	r0 = cpsr

内存操作指令:
load/store指令
标号寻址:
ldr r0, fun    将标号地址处的数值加载到r0
ldr r0, =fun   将标号表示的地址传递给r0
单寄存器操作:
ldr  从指定内存地址加载一个内容到寄存器
str  保存一个寄存器4字节数据到指定内存
ldr r0, [r1]   ==== r0 = *r1
str r0, [r1]   ==== *r1 = r0
偏移量可以是数值或寄存器。
STR<c> <Rt>, [<Rn>{, #+/-<imm12>}]    前索引寻址,不改变r1的数值(r1存的是地址,即地址不偏移)   
str r0, [r1, #4]   *(r1+4) = r0  r1=r1		
STR<c> <Rt>, [<Rn>], #+/-<imm12>      后索引寻址, 
	str r0, [r1], #4   *r1 = r0  r1=r1+4
STR<c> <Rt>, [<Rn>, #+/-<imm12>]!		基址变址寻址
	str r0, [r1, #4]!   *(r1+4) = r0  r1=r1+4
		
		ldr r0, [r1, #4]   ==== r0 = *(r1+4)   r1=r1
		ldr r0, [r1], #4   ==== r0 = *r1  r1=r1+4
		ldr r0, [r1, #4]!   ==== r0 = *(r1+4) r1=r1+4
		“!”   表示更新基地址
ldrb/strb   8位,使用寄存器的低8位
ldrh/strh   16位操作,使用寄存器的低16位
ldr/str     32位操作
ldrd/strd   64位操作
用法和32位的ldr/str一样。
保存:将寄存器的数据保存到内存
加载:将内存里的数据传输到寄存器中



多寄存器操作(块拷贝):
遵守的规则:小编号寄存器对应低地址空间
ldm  加载连续内存空间数据到多个寄存器
LDM<c> <Rn>{!}, <registers>
ldm r0, {r1,r2,r3}   ==== r1 = *r0  r2 = *(r0+4)   r3=*(r0+8)   r0=r0//注意r0的地址不变
stm  将多个寄存器的内容保存到内存中
stm r0, {r1,r2,r3}   ==== *r0=r1  *(r0+4)=r2   *(r0+8)=r3   r0=r0
ldm r0, {r1-r4, r8}
ldm r0!, {r1,r2,r3}   ==== r1 = *r0  r2 = *(r0+4) r3=*(r0+8) r0=r0+8
stm r0!, {r1,r2,r3}   ==== *r0=r1  *(r0+4)=r2 *(r0+8)=r3 r0=r0+8

ldmia/stmia    先内存操作,后地址-4
ldmda/stmda   先内存操作,后地址+4
ldmdb/stmdb    先地址-4,后内存操作
ldmib/stmib    先地址+4,后内存操作
(找规律记忆)

栈的使用:
满减栈(默认使用此栈):栈的生长方向减小,sp指向的空间不能直接使用。
满增栈:栈的生长方向增大,sp指向的空间不能直接使用。
空减栈:栈的生长方向减小,sp指向的空间可以直接使用。
空增栈:栈的生长方向增大,sp指向的空间可以直接使用。
入栈指令:stmdb sp!,{r0-r12,lr}  先减再存
出站指令:ldmia sp!,{r0-r12,pc}  先出再加
栈的操作指令:
ldmfd/stmfd  满减栈		stmfd sp!,{r0-r12,lr}	ldmfd sp!,{r0-r12,pc}
ldmfa/stmfa  满增栈
ldmea/stmea    满增栈
ldmed/stmed    满增栈
stmfd sp!,{r0-r12,lr}   ldmfd sp!,{r0-r12,pc}^    ^表示模式恢复,程序异常跳转时候最好加^,不加^只是数据恢复,但是模式不会恢复。

push {r0-r12,lr}
pop {r0-r12,pc}

协处理器操作指令:
Arm有16个协处理器 ,cp15协处理器可以设置,其他的不可以设置
CP15协处理器有16个32位的寄存器 c0-c15
mrc指令将协处理器寄存器中的数据传送到 ARM 处理器的寄存器中.若协处理器不能完成该操作,	产生未定义的异常中断。
mrc p15, 0, r0, c0, c0, 0 //将cp15协处理器的c0寄存器数值以c0,0的格式读取到r0
mcr指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中.若协处理器不能成功地执行该操作,将产生未定义指令异常中断.。  

ARM的几种寻址方式:
寄存器寻址
寄存器间接寻址 
立即数寻址
寄存器偏移寻址
多寄存器寻址
栈寻址
相对寻址
基址寻址
相对寻址

BSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是:可读写的,在程序执行之前BSS段会自动清0。所以,未初始的全局变量在程序执行之前已经成0了。

static分为三种:修饰局部变量,程序执行之后才会回收变量空间
修饰全局变量,该全局变量只在本.c使用
修饰函数,只在本.c中使用

复制代码

转载于:https://juejin.im/post/5b570e265188251af86bf119

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值