用ARM进行汇编语言编程(5) 使用链接寄存器进行分支并返回和从堆栈内存中保存和检索数据

发布于:2022-12-30 ⋅ 阅读:(136) ⋅ 点赞:(0)

ARM 编程模拟器

ARM 编程模拟器网站地址:

https://cpulator.01xz.net/?sys=arm-de1soc

在汇编里也有函数的概念,我们将使用函数看看如何调用一个位置并返回

调用:在程序里移动到不同的标签,然后执行标签里的内容

使用链接寄存器进行分支并返回

假设我要写一个程序,作用是将两个数值相加,然后将这个功能设置为一个函数,以便重复利用

首先我们随便移动一些值到寄存器里

.global _start
_start:
	mov r0,#1
	mov r1,#3

然后写一个分支,作用是相加两个寄存器的值

.global _start
_start:
	mov r0,#1
	mov r1,#3
	bal add2   //跳转到add2分支里执行内容

add2:
	add r2,r0,r1   //r2 = r0 + r1

在这里插入图片描述

然后按f5执行程序,可以看到,这个程序以我们想要的方式执行了

在这里插入图片描述

但现在的问题是,如果我想在函数调用后继续执行主函数里的内容,但是在这里调用之后就退出程序了

我们可以添加一个返回地址就能回到主函数里了

.global _start
_start:
	mov r0,#1
	mov r1,#3
	bl add2   //bl:跳转指令,用于返回到跳转指令之后的那个指令继续执行
	mov r3,#3

add2:
	add r2,r0,r1

在使用了bl指令之后,在寄存器中有一个叫做lr的链接寄存器,作用是保存子程序返回地址,然后我们执行程序看看

在这里插入图片描述

在实行了跳转之后,lr寄存器里的值就是之后mov操作的地址

之后可以使用bx指令

bx:跳转到指定寄存器里的位置
.global _start
_start:
	mov r0,#1
	mov r1,#3
	bl add2
	mov r3,#3

add2:
	add r2,r0,r1
	bx lr   //跳转到lr链接寄存器里的位置

在这里插入图片描述

然后我们执行完整的程序看看

在这里插入图片描述

可以看到成功返回到了主函数里继续执行mov的操作了

从堆栈内存中保存和检索数据

在我们写程序时,为了进行不同的计算,我们需要在写的过程中使用不同的寄存器,但他内部的寄存器是有限的,该怎么办呢

我们可以在使用后恢复原来寄存器里的值
这里写一个简单的小程序来演示,首先移动一些值到寄存器里

.global _start
_start:
	mov r0,#1
	mov r1,#3

然后我们调用一个函数,移动一些值到相同的寄存器里,然后相加,最后返回

.global _start
_start:
	mov r0,#1
	mov r1,#3
	bl baimao   //跳转到baimao分支里执行内容
baimao:
	mov r0,#5
	mov r1,#5
	add r2,r0,r1   //r2 = r0 + r1
	bx lr   //跳转到lr链接寄存器里的位置

在这里插入图片描述

当我们进入baimao这个函数时,r0和r1寄存器里的值将被覆盖

在这里插入图片描述

我们可以将r0和r1寄存器的值push进堆栈中,这样做的目的是,当程序执行完之后,我们还可以pop出堆栈,还原寄存器里的数值

.global _start
_start:
	mov r0,#1
	mov r1,#3
	push {r0,r1}   //将r0和r1寄存器里的值push进堆栈
	bl baimao
	pop {r0,r1}  //在函数执行完之后,将堆栈里的值弹出来,还原寄存器里的数值
	b end  //跳转到end分支,结束程序
baimao:
	mov r0,#5
	mov r1,#5
	add r2,r0,r1
	bx lr   //跳转到lr链接寄存器里的位置
end:

在这里插入图片描述

然后我们运行程序,看看会发生什么

在执行了push操作后,可以在内存中发现1,3数值

在这里插入图片描述

在这里插入图片描述

而sp寄存器指向了存储值的位置,之后pop的时候可以直接还原寄存器里的值

sp:堆栈指针寄存器

在这里插入图片描述

继续执行,可以看到我们的数据被覆盖了

在这里插入图片描述

返回执行了pop之后,值就还原了

在这里插入图片描述

总结

这是我学习的笔记,有什么错误和不懂的地方欢迎来私信我,或者加我qq