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


    ARM 编程模拟器

    ARM 编程模拟器网站地址:

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

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

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

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

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

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

    .global _start
    _start:
    	mov r0,#1
    	mov r1,#3
    
    • 1
    • 2
    • 3
    • 4

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

    .global _start
    _start:
    	mov r0,#1
    	mov r1,#3
    	bal add2   //跳转到add2分支里执行内容
    
    add2:
    	add r2,r0,r1   //r2 = r0 + r1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

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

    在这里插入图片描述

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

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

    .global _start
    _start:
    	mov r0,#1
    	mov r1,#3
    	bl add2   //bl:跳转指令,用于返回到跳转指令之后的那个指令继续执行
    	mov r3,#3
    
    add2:
    	add r2,r0,r1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    在这里插入图片描述

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

    之后可以使用bx指令

    bx:跳转到指定寄存器里的位置
    
    • 1
    .global _start
    _start:
    	mov r0,#1
    	mov r1,#3
    	bl add2
    	mov r3,#3
    
    add2:
    	add r2,r0,r1
    	bx lr   //跳转到lr链接寄存器里的位置
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

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

    在这里插入图片描述

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

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

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

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

    .global _start
    _start:
    	mov r0,#1
    	mov r1,#3
    
    • 1
    • 2
    • 3
    • 4

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

    .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链接寄存器里的位置
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    当我们进入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:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

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

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

    在这里插入图片描述

    在这里插入图片描述

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

    sp:堆栈指针寄存器
    
    • 1

    在这里插入图片描述

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

    在这里插入图片描述

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

    在这里插入图片描述

    总结

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

  • 相关阅读:
    Apache Dubbo 首个 Node.js 3.0-alpha 版本正式发布
    Vscode 设置clang-format
    01SpringBoot介绍
    vue使用&Mac+idea的vue开发环境配置
    XSS攻击理解与预防
    【面试总结大纲】
    监控基本概念
    C++智能指针[下](shared_ptr/weak_ptr/循环引用/删除器)
    Wireshark软件的使用教程
    kubenates的傻瓜式部署教程(K8S部署教程)
  • 原文地址:https://blog.csdn.net/qq_45894840/article/details/126676542