ARM:特殊功能寄存器、Load/Store内存读写指令、栈操作指令

1.特殊功能寄存器读写指令

msr -->>将普通寄存器中的数据写到特殊寄存器中

mrs -->>将特殊寄存器中的数据写到普通寄存器中

注:特殊寄存器 cpsr 的读写访问只能使用 msr 和 mrs 指令

.text	/* 代码段 */
/* 将_start 声明为一个全局的函数, _start表示汇编程序的入口 */
.globl _start	/* globl 与 global 效果一样 */

_start:	/* 标签 : 类似于C语言的函数的名字, 表示函数的入口地址 */
    /*
	格式
		msr cpsr, 普通寄存器/立即数	@ cpsr = 普通寄存器/立即数
		mrs Rd, cpsr	@ Rd = cpsr
	*/

	@ 系统上电默认是svc 模式
	@ 修改系统模式到用户模式
	@ svc模式(10011) -->> 用户模式(10000)
	@ 1101 0011 -->> 1101 0000
	
	@ 1.通过 msr 直接修改
	@msr cpsr, #0xd0
	
	@ 2.通过位运算的方式
	mrs r0, cpsr
	bic r0, r0, #0x1f  @将[4:0]位清零
	orr r0, r0, #0x10
	msr cpsr, r0
		
	stop:
		b stop
.end

2.Load/Store内存读写指令

2.1单寄存器操作指令

ldr -->>将内存中的数据读到普通寄存器中,读4个字节的大小

str -->>将普通寄存器中的数据写到内存中,写4个字节的大小

ldrh -->>将内存中的数据读到普通寄存器中,读2个字节的大小

strh -->>将普通寄存器中的数据写到内存中,写2个字节的大小

ldrb -->>将内存中的数据读到普通寄存器中,读1个字节的大小

strb -->>将普通寄存器中的数据写到内存中,写1个字节的大小

.text	/* 代码段 */
/* 将_start 声明为一个全局的函数, _start表示汇编程序的入口 */
.globl _start	/* globl 与 global 效果一样 */

_start:	/* 标签 : 类似于C语言的函数的名字, 表示函数的入口地址 */
	/*
	其他用法:
	@ 将[Rm + offset]地址中的内容读到Rd寄存器中,Rm中的值不变
	ldr/ldrh/ldrb  Rd, [Rm, #offset]  
	@ 将[Rm]地址中的内容读到Rd寄存器中, 同时更新Rm中的地址:Rm=Rm+offset
	ldr/ldrh/ldrb  Rd, [Rm], #offset  
	@ 将[Rm + offset]地址中的内容读到Rd寄存器中,同时更新Rm中的地址:Rm=Rm+offset
	@ ! : 更新地址
	ldr/ldrh/ldrb  Rd, [Rm, #offset]!  
	
	@ 将Rn寄存器中的数据写到[Rm + offset]地址中,Rm中的值不变
	str/strh/strb  Rn, [Rm, #offset]
	@ 将Rn寄存器中的数据写到[Rm]地址中,同时更新Rm中的地址:Rm=Rm+offset
	str/strh/strb  Rn, [Rm], #offset
	@ 将Rn寄存器中的数据写到[Rm + offset]地址中,同时更新Rm中的地址:Rm=Rm+offset
	str/strh/strb  Rn, [Rm, #offset]!
	
offset : 偏移地址,偏移地址的大小是Load/Store指令可访问空间大小的整数倍。
	*/
	
	.if 0
		ldr r0, =0x12345678
		ldr r1, =0x40000800
		@ 将 r0 中的数据写到 [r1] 指向的地址空间
		str r0, [r1]
		@ 将 [r1] 指向的地址空间的数据读到r2寄存器中
		ldr r2, [r1]
	.endif
		ldr r0, =0x40000800
		ldr r1, =0x11111111
		ldr r2, =0x22222222
		ldr r3, =0x33333333
		@ 将r1中的数据写到[r0+4]地址中,r0中的值不变
		@ [0x40000804] = 0x11111111 , r0 = 0x40000800
		str r1, [r0, #4]
		
		@ 将r2中的数据写到[r0]地址中,同时更新r0中的地址,r0=r0+4
		@ [0x40000800] = 0x22222222 , r0 = 0x40000804
		str r2, [r0], #4
		
		@ 将r1中的数据写到[r0+4]地址中,同时更新r0中的地址,r0=r0+4
		@ [0x40000808] = 0x33333333 , r0 = 0x40000808
		str r3, [r0, #4]!
	
		
	stop:
		b stop
.end

执行结果:

2.2多寄存器操作指令(ldm、stm)

.text	/* 代码段 */
/* 将_start 声明为一个全局的函数, _start表示汇编程序的入口 */
.globl _start	/* globl 与 global 效果一样 */

_start:	/* 标签 : 类似于C语言的函数的名字, 表示函数的入口地址 */
	/*
	ldm Rm, {寄存器列表}
		将Rm指向的连续的地址空间中的数据读到寄存器列表的每个寄存器中

	stm Rm, {寄存器列表}
		将寄存器列表中的每个寄存器中的数据写到Rm指向的连续的地址空间中
	
使用注意:
	1. Rm寄存器中的数据被当成一个地址看待
	2. 寄存器列表中的寄存器如果是连续的则使用"-"隔开;
	3. 寄存器列表中的寄存器如果不连续则使用","隔开;
	4. 寄存器列表中的寄存器要求从小到大依次书写,
		如果从大到小书写,要求依次用逗号隔开书写,但编译器会报警告。
	*/
	@ 不管寄存器列表中的寄存器的顺序如何书写,
	@ 永远都是小编号的寄存器对应低地址;
	@ 大编号的寄存器对应高地址
	
	ldr r0, =0x40000800
	ldr r1, =0x11111111
	ldr r2, =0x22222222
	ldr r3, =0x33333333
	ldr r4, =0x44444444
	@ 将r1-r4寄存器中的数据写到r0指向的连续的16字节空间中
	stm r0, {r1-r4}
	@ 将r0指向的连续的16字节空间的数据读到r5-r8中
	ldm r0, {r5-r7,r8}
		
	stop:
		b stop
.end

执行结果:

 3.栈操作指令

1> 增栈: 压栈之后,栈指针向高地址方向移动。

2> 减栈: 压栈之后,栈指针向低地址方向移动。

3> 空栈: 当前栈指针指向的空间没有有效的数据,因此可以先压栈,压栈之后栈指针指向的空间就有有效的数据,因此需要移动栈指针,让栈指针指向一个没有有效数据的空间。

4> 满栈: 栈指针指向的空间有有效的数据,需要先移动栈指针,让栈指针指向一个空的位置,在进行压栈的操作,压制之后此时栈指针指向的空间又有有效的数据。

3.1栈的操作方式

栈的操作方式都是组合来使用的

满增栈 : Full Ascending -----> stmfa/ldmfs

满减栈 : Full Descending -----> stmfd/ldmfd

空增栈 : Empty Ascending -----> stmea/ldmea

空减栈 : Empty Descending -----> stmed/ldmed

ARM处理器默认采用的是满减栈,ARM指令集本身是支持以上4种栈的操作方式的所有的指令。

.text	/* 代码段 */
/* 将_start 声明为一个全局的函数, _start表示汇编程序的入口 */
.globl _start	/* globl 与 global 效果一样 */

_start:	/* 标签 : 类似于C语言的函数的名字, 表示函数的入口地址 */
	/*
	指令格式
	ldmfd sp!, {寄存器列表}
		将sp指向的栈空间中的数据读到寄存器列表的每个寄存器中

	stmfd sp!, {寄存器列表}
		将寄存器列表中的每个寄存器中的数据写到sp指向的栈空间中
	
使用注意:
	0. ! : 压栈和出栈之后都需要更新栈指针
	1. sp寄存器中的数据被当成一个栈空间的地址看待
	2. 寄存器列表中的寄存器如果是连续的则使用"-"隔开;
	3. 寄存器列表中的寄存器如果不连续则使用","隔开;
	4. 寄存器列表中的寄存器要求从小到大依次书写,
		如果从大到小书写,要求依次用逗号隔开书写,编译器会报警告。
	*/
	
	ldr sp, =0x40000800    @ 初始化sp的地址
	
	mov r0, #1
	mov r1, #2
	
	bl add_func1
	add r2, r0, r1
	nop
	b stop
	
	
	add_func1:
	stmfd sp!, {r0-r1, lr}
	mov r0, #3
	mov r1, #4
	bl add_func
	add	r3, r0, r1
	ldmfd sp!, {r0-r1, lr}	@ 也可以写成ldmfd sp!, {r0-r1, pc}
	mov pc, lr				
	
	
	add_func:
	stmfd sp!, {r0,r1}
	mov r0, #5
	mov r1, #6
	add r4, r0, r1
	ldmfd sp!, {r0,r1}
	mov pc, lr
		
	stop:
		b stop
.end

执行结果;

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340