堆栈指针寄存器 SP详解以及栈的作用

堆栈指针寄存器 SP详解以及栈的作用本文引用地址 http www eepw com cn article 201611 321963 htm 韦东山 https blog csdn net thisway diy article details 76422943 堆栈是一种具有 后进先出 LIFO LastInFirstO 特殊访问属性的存储结构 堆栈一般使用 RAM 物理资源作为存储体 再加上 LI

本文引用地址:http://www.eepw.com.cn/article/201611/321963.htm

韦东山:https://blog.csdn.net/thisway_diy/article/details/76422943 


堆栈是一种具有“后进先出”(LIFO—Last In First Out)特殊访问属性的存储结构。堆

栈一般使用RAM 物理资源作为存储体,再加上LIFO 访问接口实现。

http://editerupload.eepw.com.cn/fetch/20161101/321963_1_0.jpg

堆栈的实现方法:

随机存储器区划出一块区域作为堆栈区,数据可以一个个顺序地存入(压入)到这个区域之中,这个过程称为‘压栈’(push )。通常用一个指针(堆栈指针 SP—StackPointer)实现做一次调整,SP总指向最后一个压入堆栈的数据所在的数据单元(栈顶)。从堆栈中读取数据时,按照堆栈 指针指向的堆栈单元读取堆栈数据,这个过程叫做 ‘弹出’(pop ),每弹出一个数据,SP 即向相反方向做一次调整,如此就实现了后进先出的原则。

堆栈是计算机中广泛应用的技术,基于堆栈具有的数据进出LIFO特性,常应用于保存中断断点、保存子程序调用返回点、保存CPU现场数据等,也用于程序间传递参数。

ARM处理器中通常将寄存器R13作为堆栈指针(SP)。ARM处理器针对不同的模式,共有 6 个堆栈指针(SP),其中用户模式和系统模式共用一个SP,每种异常模式都有各自专用的R13寄存器(SP)。它们通常指向各模式所对应的专用堆栈,也就是ARM处理器允许用户程序有六个不同的堆栈空间。这些堆栈指针分别为R13、R13_svc、R13_abt、R13_und、R13_irq、R13_fiq,如表2-3堆栈指针寄存器所示。

http://editerupload.eepw.com.cn/fetch/20161101/321963_1_1.jpg

为了更准确地描述堆栈,根据“压栈”操作时堆栈指针的增减方向,将堆栈区分为‘递增堆栈’(SP 向大数值方向变化)和‘递减堆栈’(SP 向小数值方向变化);又根据SP 指针指向的存储单元是否含有堆栈数据,又将堆栈区分为‘满堆栈’(SP 指向单元含有堆栈有效数据)和‘空堆栈’(SP 指向单元不含有堆栈有效数据)。

这样两两组合共有四种堆栈方式——满递增、空递增、满递减和空递减。

ARM处理器的堆栈操作具有非常大的灵活性,对这四种类型的堆栈都支持。

ARM处理器中的R13被用作SP。当不使用堆栈时,R13 也可以用做通用数据寄存器。

栈的整体作用:

1. 保护现场

现场/上下文相当于案发现场,总有一些案发现场,要记录下来,否则被别人破坏,便无法恢复。而此处说的现场,是指CPU运行时,用到的一些寄存器,比如r0,r1等,对于这些寄存器的值,如果不保存而直接跳转到子函数中执行,其很可能被破坏,因为其函数执行也要用到这些寄存器。因此,在函数调用之前,应该将这些寄存器等现场暂时保存(入栈push),等调用函数执行完毕后出栈(pop)再恢复现场。这样CPU就可以正确的继续执行了。

保存寄存器的值,一般用push指令,将对应的某些寄存器的值,一个个放到栈中,即所谓的压栈。然后待被调用的子函数执行完毕后再调用pop,把栈中的一个个的值,赋值给对应的那些你刚开始压栈时用到的寄存器,把对应的值从栈中弹出去,即所谓的出栈。

其中保存的寄存器中,也包括lr的值(因为用bl指令进行跳转的话,之前的pc值存在lr中),在子程序执行完毕后,再把栈中的lr值pop出来,赋值给pc,这样就实现了子函数的正确的返回。

2. 传递参数

3. 临时变量保存在栈中

这些临时变量包括函数的非静态局部变量以及编译器自动生成的其他临时变量

举例分析C语言函数调用如何使用栈

上面的解释有些抽象,此处再用例子简单说明一下,就容易明白了: 

用arm-inux-objdump –d u-boot dump_u-boot.txt得到dump_u-boot.txt文件。该文件是包含了u-boot可执行汇编代码,从中我们可以看到相应C程序对应的汇编代码。

下面贴出两个函数的汇编代码,一个是clock_init,另一个是与clock_init在同一C源文件中的函数CopyCode2Ram:

33d0091c: CopyCode2Ram: 33d0091c: e92d4070 push {r4, r5, r6, lr} 33d00920: e1a06000 mov r6, r0 33d00924: e1a05001 mov r5, r1 33d00928: e1a04002 mov r4, r2 33d0092c: ebffffef bl 33d008f0 b BootFrmNORFlash ...... 33d00984: ebffff14 bl 33d005dc nand_read_ll ...... 33d009a8: e3a00000 mov r0, #0 ; 0x0 33d009ac: e8bd8070 pop {r4, r5, r6, pc} 33d009b0:clock_init: 33d009b0: e3a02313 mov r2, # ;0x4c000000 33d009b4: e3a03005 mov r3, #5 ; 0x5 33d009b8: e str r3, ...... 33d009f8: e1a0f00e mov pc, lr 

 

(1) 先分析clock_init对应的汇编代码,可以看到该函数第一行 
:33d009b0: e3a02313 mov r2, # ;0x4c000000 
没有我们期望的push指令,即没有将一些寄存器的值放入栈。这是因为,clock_init用到的r2,r3等寄存器,和前面调用clock_init前用到的寄存器r0,没有冲突,故此处不用push保存,有个寄存器要注意,r14,即lr,前面调用clock_init时,用的bl指令,所以会自动把跳转时的pc值赋值给lr,所以也不需要push将PC值保存到栈。而clock_init对应的汇编代码最后一行: 33d009f8: e1a0f00e mov pc, lr 就是我们常见的mov pc,lr,把lr值,即之前保存的函数调用时的PC值,赋值给现在的PC,这样便实现了函数的正确返回,即返回到了函数调用时下一个指令的位置。CPU可以继续执行原先函数内剩下的代码。




(2) CopyCode2Ram对应汇编代码第一行:33d0091c: e92d4070 push {r4, r5, r6, lr} 
就是我们所期望的,用push保存r4,r5,r6,lr,是因为此函数还包括其他函数调用 
:33d0092c: ebffffef bl 33d008f0 b BootFrmNORFlash…… 
33d00984: ebffff14 bl 33d005dc nand_read_ll 
…… 
也用到bl指令,会改变我们最开始进入clock_init时的lr值,所以也要push暂时保存起来。










而对应地,CopyCode2Ram最后一行:33d009ac: e8bd8070 pop {r4, r5, r6,pc}是把之前push的值给pop出来,还给对应的寄存器,其中最后一个是将开始push的lr的值pop出来赋给PC,实现了函数的返回。另外我们注意到,CopyCode2Ram的倒数第二行:33d009a8: e3a00000 movr0, #0 ; 0x0 是把0赋值给r0寄存器,就是我们说的返回值的传递,此处的返回值为0,也对应着C代码中的“ return 0”。

当然也可以用其他暂时空闲没有用到的寄存器来传递返回值。

 

 

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

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/208540.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午11:21
下一篇 2026年3月19日 上午11:21


相关推荐

  • K-means聚类算法原理及python实现

    K-means聚类算法原理及python实现文章目录一 聚类算法二 K means 聚类算法三 K means 算法步骤详解 Step1 K 值的选择 Step2 距离度量 2 1 欧式距离 2 2 曼哈顿距离 2 3 余弦相似度 Step3 新质心的计算 Step4 是否停止 K means 四 K means 算法代码实现 1 其伪代码如下 2 python 实现五 K means 算法补充六 小结一 聚类算法 nbsp nbsp nbsp nbsp amp nbs

    2026年3月26日
    2
  • windows 通过whl文件安装dlib

    windows 通过whl文件安装dlib一 nbsp dlib nbsp 1 下载 whl 文件 nbsp nbsp nbsp 从 https pypi org simple dlib nbsp 下载 dlib 19 8 1 cp36 cp36m win amd64 whl 到本地 nbsp 2 nbsp pipinstallE software dlib 19 8 1 cp36 cp36m win amd64 whl nbsp 3 测试 nbsp 二 nbsp face recogn

    2026年3月26日
    1
  • Vsftp与PAM虚拟用户

    Vsftp与PAM虚拟用户Vsftp与PAM虚拟用户使用yum安装vsftpyum install vsftpd pam pam-* db4 db4-* 创建一个保存用户及密码的文件cd /etc/vsftpd/ touch virtual_login 添加用户(一行用户一行是密码)vim  virtual_login dongnan nandong

    2025年6月23日
    8
  • 仿QQ联系人的TableView的折叠与拉伸

    仿QQ联系人的TableView的折叠与拉伸

    2022年3月12日
    70
  • WPF TextBox模仿PasswordBox的密码显示功能

    WPF TextBox模仿PasswordBox的密码显示功能WPFTextBox显示密码,模仿PasswordBox的功能

    2022年7月24日
    17
  • VS注释快捷键整理

    VS注释快捷键整理在 VisualStudio 中使用快捷键注释代码 无论是行注释还是块注释 第一步一定是选中要注释的内容 取消注释同样要先选中 当然 如果是行注释 不必选取整行 将光标定位到该行即可 下面整理一下 VisualStudio 中行注释和块注释的快捷键 以及快捷键的查看与修改 行注释行注释有以下两种方式 方式一 注释 Ctrl K Ctrl C 取消 Ctrl K Ctrl U 方式二 注释和取消都是这组快捷键 Ctrl K Ct

    2026年3月20日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号