【ARM】-栈帧

article/2025/10/18 19:35:19

ARM 栈帧

本系列均以 corter-A7(armv7-a) 为例

在 ARM 中,通常为满减栈(Full Descending FD), 也就是说,堆栈指针指向堆栈内存中最后一个填充的位置,并且随着每个新数据项被压入堆栈而递减。

栈的本质

要理解栈的本质,首先得明白,程序执行是怎么执行的?

程序执行其实就是对应一个又一个状态机,在 A 状态有对应的内核寄存器,在 B 状态也有对应的内核寄存器值。

A 状态切换到 B 状态,就需要把 A 状态的内核寄存器保存下来,不然无法从 B 状态再回到 A 状态。此时就需要将 A 状态下内核寄存器的值放到内存中,即入栈

B 状态切换到 A 状态,需要恢复 A 状态的现场,即内核寄存器的值,所以需要将存到内存中的数据写回到内核寄存器,即出栈

其实 linux/rtos 的任务也是一个又一个状态机,状态切换的时候,先将当前状态(A)的内核寄存器保存到内存中,再把下一个状态(B)的内核寄存器从内存中读回来,程序跳转到 B 状态执行,其实这就是上下文切换的过程。

入栈/出栈的本质其实就是内存中的一块区域进行操作:

  • 需要入栈的时候,就把内核寄存器的值写入到内存中
  • 需要出栈的时候,就把相应内存中的值写回到内核寄存器中

入栈

在这里插入图片描述
在调用入栈指令 PUSH/STMFD 之前,堆栈指针(SP)指向堆栈中最后一个被占用的字节,入栈指令完成后,堆栈指针被递减8(两个字),并且这两个字的内容被写入内存。

编号低的寄存器写入内存低地址处

出栈

假设要将:R0-R3 和 LR 寄存器入栈,当前的 SP 指针指向 0x80000000,由于 ARM 处理器的栈是向下增长的,使用的汇编代码如下:PUSH {R0-R3,LR}

入栈之后,内存分布如下
在这里插入图片描述

假设这个时候又对 LR 进行入栈操作,汇编代码如下:PUSH LR

入栈之后,内存分布如下

在这里插入图片描述
上面两个图就是分步对 R0-R3,R12,及 LR 进行压栈以后的编程模型,如果要出栈的话,就使用如下代码:

POP LR
POP {R0-R3,R12}

出栈的时候从栈顶开始,也就是 SP 当前执行的位置,地址依次增大,提取堆栈中的数据到要恢复的寄存器列表中。
PUSH 和 POP 的另一种写法是 STMFD SP! 和 LDMFD SP!
因此上面的代码可以写为

入栈
STMFD SP!,{R0~R3, R12}
STMFD SP! ,{LR}
出栈
LDMFD SP! ,{LR}
LDMFD SP! ,{R0~R3, R12}

示例测试

gdb 小技巧:

  • 窗口缩小:winheight src -5
  • 窗口放大:winheight src +5

入栈

入栈之前先查看当前寄存器
在这里插入图片描述

  • Info reg:从内核寄存器中可以看到,当前 r0 r1 r2 r3 lr 寄存器的值依次为:1 2 3 4 5
    sp 指针当前为0x801fffec

  • x/20 0x801fffec 查看 SP 栈指针地址数据
    在这里插入图片描述

可以看到 SP 地址数据从高到低依次为:5 4 3 2 1

从这里可以看到,编号低的寄存器写入内存低地址处

寄存器清零

在这里插入图片描述

出栈

在这里插入图片描述

源码

.global _start_start:/* 进入 SVC 模式(其实复位之后,系统就处于 SVC 模式,这里也可以不切换,设置 SP 的值) */mrs r0, cpsrbic r0, r0, #0x1f /* 将  r0 寄存器中的低 5 位清零,也就是 cpsr 的 M0~M4 */orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */msr cpsr, r0      /* 将 r0 的数据写入到 cpsr 中 */ldr sp, =0X80200000	/* 设置栈指针 */ldr r0, =0x01ldr r1, =0x02ldr r2, =0x03ldr r3, =0x04ldr lr, =0x05push {r0-r3, lr}/* nop for debug */nopnopnopmov r0, #0mov r1, #0mov r2, #0mov r3, #0mov lr, #0/* nop for debug */nopnopnoppop {r0-r3, lr}/* nop for debug */nopnopnopstmfd sp!, {r0-r3, lr}/* nop for debug */nopnopnopmov r0, #0mov r1, #0mov r2, #0mov r3, #0mov lr, #0/* nop for debug */nopnopnopldmfd sp!, {r0-r3, lr}/* nop for debug */nopnopnoploop:b loop

http://chatgpt.dhexx.cn/article/EuxSqhY8.shtml

相关文章

JVM 栈和栈帧

tag: jvm,stack,stack frame,栈,栈帧 原文:JVM Stacks and Stack Frames 翻译:陈同学 欢迎访问陈同学博客原文,文章可读性更佳 前情提要 对于没有深度递归的函数来说,无需担心上篇文章中的算法。当知道正在处理数据集有限时&am…

C语言的函数栈帧

⭐️前面的话⭐️ 📒博客主页:未见花闻的博客主页 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📌本文由未见花闻原创,CSDN首发! ✉️坚持和努力一定能换来诗与远方! &…

【C语言】函数栈帧的创建和销毁(1)

前言: ❓ 在我们前期学习C语言时,你是否曾产生过很多困惑? 💭 比如:局部变量是怎么创建出来的?因为局部变量的值是随机值,我们建议将它初始化,那么为什么局部变量的值是随机值&am…

函数栈帧(详解版)

文章目录 前言1.浅谈C语言内存1.1 内存分配1.2 栈1.3 寄存器 2. 为main()函数开辟栈帧3.变量的初始化及函数调用4.ADD函数4.1 ADD函数的创建4.2 ADD函数使用与销毁 5.总结 前言 前期学习的时候,我们可能有很多困感? 比如: ●局部变量是怎么创建的?I为什么局部变量…

也谈栈和栈帧

 一个码农要是没遇见过coredump,那他就是神仙了。core file(coredump的转储文件)中保存的最重要内容之一,就是函数的call trace。还原这部分内容 (栈回溯) ,并与原代码对应上,尽快找出程序崩溃的位置和…

(栈帧和函数调用一)栈帧,函数调用与栈的关系

(栈帧和函数调用一)栈帧,函数调用与栈的关系 一,栈帧的介绍二,函数调用与栈的关系三,汇编演示四,总结 在计算机科学中,栈是一个特殊的容器,用户可以将数据压入栈中&#…

理解栈帧和栈的运行原理

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法 (Method) 和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧 F1,并被压入到栈中&…

函数栈帧的形成与释放

✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!! 📃个人主页:rivencode的个人主页 🔥系列专栏:玩转C语言 💬推荐一…

【函数栈帧的创建和销毁】(超详细图解)

想必大家在学完C语言函数章节之后,是否有这样的困惑: 局部变量是怎么创建的 ? 为什么局部变量的值是随机值 ? 函数是怎么传参的?传参的顺序又是什么样的 ? 形参和实参是什么关系 ? 函数调用…

C语言函数栈帧详解

系列文章目录 前言 最近正在学习栈帧方面的知识,由于本人对汇编不太熟悉,对其中频繁出现的ESP寄存器和EBP寄存器一直没搞清楚,在查找资料后,在此进行整理,方便以后温故知新。 一、预备知识 要清楚理解栈帧的概念&…

详解栈帧结构

https://www.1024do.com/?p367 栈帧结构 含义:C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现过程函数调用的一种数据结构。 从逻辑上讲,栈帧就是…

函数栈帧详解

目录 一.什么是函数栈帧 1.寄存器: 2.函数栈帧 3.栈帧的作用和维护 4.栈帧结构 二.函数栈帧的创建 1.汇编代码 2.main函数函数栈帧的创建 1.汇编语言讲解: 2.栈帧创建: 3.详细步骤 3.ADD函数栈帧的创建 栈帧创建: 3.函…

栈帧

首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(地址地)。下图为典型的存取器安排,观察栈在其中的位置 入栈操…

什么是函数栈帧

函数栈帧的创建与销毁 一、函数栈帧的创建1.寄存器2.函数栈帧3.函数中调用函数 二、函数栈帧的销毁总结 一、函数栈帧的创建 1.寄存器 一般来说,计算机中的寄存器有六种 分别是:eax, ebx, ecx,edx,ebp,esp 而ebp,esp这两个寄存器中存放的是地址&#…

栈帧 stack frame

栈帧 stack frame 每一次函数调用都会维护一个栈帧(stack frame),栈帧主要用于传递参数、保存返回地址、保存局部变量等。先直接上一个《深入理解计算机系统》上的原图。 其中,%rsp 指向栈顶位置,%rbp 指向栈底位置。…

C/函数栈帧

🌱博客主页:大寄一场. 🌱系列专栏:C语言学习笔记 😘博客制作不易欢迎各位👍点赞⭐收藏➕关注 ​ 目录 前言 寄存器 1. 寄存器的种类与功能 C语言汇编指令介绍 函数栈帧的创建与销毁过程 1.函数栈帧的…

浅谈函数栈帧(Stack Frame)

💙作者:阿润菜菜 📖专栏:C 本文目录 什么是栈帧 在调试中观察 总结 什么是栈帧 那我们先来看看什么是栈: 栈(stack)是限定仅在表尾进行插入或者删除的线性表。栈是一种数据结构,它按照后进先出的原则存储…

栈和栈帧

栈 堆栈(stack)又称为栈或堆叠,是计算机科学里最重要且最基础的数据结构之一,它按照FILO(First In Last Out,后进先出)的原则存储数据。 栈的相关概念: 栈顶和栈底:允许元素插入与删除的一端…

函数栈帧的创建和销毁(图解)

目录 基础知识介绍1. 寄存器的种类与功能2. 常用汇编指令3. 内存模型 演示函数栈帧的创建销毁过程1. 为main()函数开辟栈帧2. 在main()函数中创建变量3. 调用Add()函数前的准备4. 为Add()函数开辟栈帧5. 在Add()函数中创建变量并运算6. Add()栈帧的销毁7. 返回main()函数栈帧 总…

运行时栈帧结构是怎样的?

写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java虚拟机 解答 栈帧(Stack Frame)是J…