ARM 寻址举例(19)

举例: 计算一个数组的所有元素的和。

复制代码
	area first, code, readonly                                
	code32
	entry
start
	ldr r0,=array
;	adr r0,array   ;ADR为小范围的地址读取伪指令
loop
	ldr r1,[r0],#4
	cmp r1,#0
	addne r4,r4,r1
	bne loop
stop
	b stop
	; DCD 伪操作  数据缓冲池技术   
	; dcd  机器码
array
	dcd 0x11
	dcd 0x22
	dcd 0

首先是关于 dcd 指令的解释, dcd是一个 伪指令, 表示 在内存中分配一篇连续的单元,并且复制。

ldr r0, =array , 代表的是 加载 array 的地址 到r0 寄存器。相当于 C语言的 & 符号。

ldr r1, r0, #4, 表示,将r0 的内容放到r1 , 并且r0 加4,

然后比较r1 是不是等于0 , 如果等于0 就代表已经到数组的最后了,就进入死循环,

如果不是0 , 那么就把 和 放到r4 的寄存器中。

然后是第二个例子: 内存的压栈与出栈。

复制代码
    area first, code, readonly                               
	code32
	entry
Start
   ;mov r0, #0x40000000
	ldr sp, =0x40001000  ;注意地址

	mov r1, #0x11
	mov r2, #0x22
	mov r3, #0x33
	mov r5, #0x55
	; 压栈
	stmfd sp!, {r1-r3, r5}
	;stmia r0!, {r1-r3, r5} ; 加感叹号是自动修改基地址
    mov r1, #0 
	mov r2, #0
	mov r3, #0
	mov r5, #0

	ldmfd sp!, {r1-r3, r5}
	;ldmdb r0!, {r2,r1,r3, r5} ; 寄存列表书写顺序无所谓, 低地址内容对应低编号寄存器 
stop 
	b stop 
	end

这里需要 说明的是 两个指令

STMFD 指的就是 进行压栈, LDMFD指的就是出栈。

ldr sp, =0x40001000 , 值得是在 设置栈指针。

stmfd sp!, {r1,-r3,r5}, 这里代表的是,将寄存器组的数据,压栈到 sp 指针指向的地方,并且, sp 指针,需要同步向下走。

注意: r1,r2,r3,r5 ,在往内存中压栈的时候, 顺序是这样的, 内存中的低地址,存放的是 低标号的寄存器的值。

ldmfd sp! ,{r1-r3,r5} , 代表的是,出栈的操作, 出栈的顺序也是, 低地址的内存的值,对应的是低标号的寄存器。

这样的话,就可以完美的回复到之前压栈的寄存器中。

在然后的例子就是函数的嵌套调用。

复制代码
 	area first, code, readonly                   
	code32
	entry
start
	ldr sp, =0x40002000
	mov r1, #0x11
	mov r2, #0x22
	mov r3, #0x33
	mov r5, #0x55
	bl child_func1        ; 【先写跳转到 child_func1,再写跳转到child_func】	
	add  r0, r1,r2
stop 
	b stop 
; 非叶子函数	
child_func
	stmfd sp!, {r1-r3,r5,lr} ;;;在子函数里首先将所有寄存器值压栈保存,
	                   ;;防止在子函数里篡改原本在主函数里运算需要的值,
	                   ;;通常需要把r0-r12全都保存,为了安全和程序通用性应该这么做
	mov r1, #10       ;;在这里子函数想怎么做自己的事情就可以做自己的事情
    bl child_func1
	ldmfd sp!, {r1-r3,r5,lr};;;;; 放在主函数bl之后的第一句行吗?
	mov pc, lr
child_func1
 	stmfd sp!, {r1-r3,r5};;;不论嵌套多少层子函数,都是先压栈,
  	mov r1, #11
	ldmfd sp!, {r1-r3,r5};;对应的,在返回到自己的父函数之前将自己出栈
	mov pc, lr
	end

ldr sp, =0x40002000 ,这是在设置栈指针。

bl child_func1 这是在进行跳转,这里有个隐含的操作,cpu 会自动的把下一条 PC指针的值, 放到LR寄存器中。

stmfd sp! , {r1-r3,r5,lr} , 这是在压栈, 这里特别提到了,lr ,这是把函数返回的PC值, 也压栈了。

bl child_func1 , 与之前的操作是一样的。

然后就是 返回的操作了。

ldmfd sp!, {r1-r3,r5} 这是在进行出栈了。

mov pc, lr ,这个指令就是在返回了。

相关推荐
白藏y3 分钟前
【Linux】基础 IO(一)—— 文件操作及文件系统
linux
海绵宝宝de派小星1 小时前
MCP与A2A协议深度解析:Agent时代的“TCP/IP“如何诞生
arm开发·网络协议·tcp/ip·ai
utf8mb4安全女神1 小时前
shell中的判断语法
linux·运维·服务器
mifengxing2 小时前
操作系统(五)
linux·运维·服务器·操作系统·王道考研
ALINX技术博客2 小时前
【黑金云课堂】FPGA技术教程Linux开发:NVMe/Qt/OpenCV人脸检测
linux·qt·fpga开发
kebidaixu3 小时前
OK3568 RTC 驱动适配与 Linux 系统时间管理总结
linux
戴西软件3 小时前
戴西CAxWorks.AICrash:AI+法规驱动的行人保护自动化分析
linux·运维·网络·人工智能·安全·自动化
CingSyuan3 小时前
Linux服务器数据盘初始化与盘符漂移解决方案:标准分区、LVM逻辑卷、XFS格式化、fstab配置与UUID持久化挂载实战
linux·运维·服务器
jingling5553 小时前
从零到一:用 Aholo Viewer 在浏览器里渲染 3D 高斯泼溅小熊
linux·前端·ubuntu·3d
张青贤4 小时前
centos7内核kernel升级
linux·centos·内核·kernel