ARM学习之数据栈的使用规则

本文深入解析ARM处理器的堆栈操作,包括满栈与空栈、递增与递减堆栈的概念,以及ARMv7cortex-A9架构下APCS规定的满递减数据栈。详细解释了stmfd和ldmfd指令的使用,以及数据栈指针、基地址和界限等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载来自:https://www.jianshu.com/p/6062b480d85b

关键词: arm堆栈操作,堆栈严格来说应该叫做栈,栈(stack)是限定仅在一端进行插入或删除操作的线性表。因此,对栈来说,可以进行插入或删除操作的一端称为栈顶(top),相应地,另一端称为栈底(bottom)。不含元素的空表称为空栈。由于堆栈只允许一端进行操作,因而按照后进先出(LIFO-last in first out)的原理运作。

  1. 根据堆栈指针指向位置的不同,堆栈可分为两种:满栈和空栈。
  • 满栈(full):当堆栈指针指向栈顶元素 ,即指向 最后一个入栈的元素时,称为满栈;
  • 空栈(empty):当堆栈指针指向与栈顶元素相邻的一个可用数据单元时,称为空栈。
  1. 根据数据栈增长方向的不同也可分为递增堆栈和递减堆栈2种。
  • 递减堆栈(descending):数据栈向内存地址减小的方向增长;
  • 递增堆栈(ascending):数据栈向内存地址增加的方向增长。

综合这两种特点则可有以下4种规则:

缩写名称指令含义
FD满递减stmfd/ldmfd堆栈通过减小存储器的地址向下增长,堆栈指针指向内含有效数据项的最低地址
ED空递减stmed/ldmed堆栈通过减小存储器的地址向下增长,堆栈指针指向堆栈下的第一个空位置
FA满递增stmfa/ldmfa堆栈通过增大存储器的地址向上增长,堆栈指针指向内含有效数据项的最高地址
EA空递增stmea/ldmea堆栈通过增大村吃器的地址向上增长,堆栈指针指向堆栈上的第一个空位置

有一点是需要注意的,虽然ARM处理器核对于两种生长方式的堆栈均支持,但ads的C语言编程只支持一种方式,即从上往下生长,并且必须是满递减堆栈。所以stmfd等指令用的最多。

ARMv7 cortex-A9架构下,APCS规定数据栈为满递减的。

ARM对于堆栈的操作一般采用ldmfd(pop)和stmfd(push)两个命令,以前困惑的是stmfd对于操作数是按照什么顺序压栈的,比如:stmfd sp! {r0-r5, lr} 的进栈顺序是:
a.

                            高地址
                              lr
                              r5
                              r4
                              ……
                              r0   <--sp
                              低地址

b.

                            高地址
                              r0
                              r1
                              r2
                              ……
                              lr  <--sp
                              低地址

现在通过下表就可以轻松解决这个问题:

寻址方式说明pop=ldmpush=stm
fa满递增ldmfaldmdastmfastmib
fd满递减ldmfdldmiastmfdstmdb
ea空递增ldmealdmdbstmeastmia
ed空递减ldmedldmibstmedstmda

说明:
a : after(后偏移指针)
b : before(先偏移指针)
i : increase(递增 )
d : decrease(递减)

根据图表,可知stmfd对应的是stmdb,根据arm指令手册,可知stmdb入栈顺序是方式a,而 ldmfd对应的是ldmia,这样这两个操作就可以成功配对。

  1. 相关名词:

数据栈指针: 最后一个写入栈的数据的内存地址;
数据栈的基地址: 数据栈的最高地址,由于APCS中的数据栈是FD类型的,多以最早入栈的数据所占的内存单元的基地址的下一个内存单元。
数据栈界限: 数据栈中可使用的最低的内存单元地址;
已用的数据栈: 数据栈的基地址和数据栈的栈指针之间内存区域,包括栈指针对应的内存单元,但不包括基地址对应的内存单元。



作者:A_ck
链接:https://www.jianshu.com/p/6062b480d85b
 

### ARM 架构下的多级函数调用分析与调试 在嵌入式系统开发中,特别是在基于 ARM 架构的环境中,理解并掌握函数调用的工作原理以及相应的调试技术是非常重要的。以下是关于 ARM 架构下多级函数调用工作原理及其调试方法的具体说明。 #### 函数调用的基本概念 在计算机程序运行过程中,每当进入一个新的函数时,都会创建一个称为“帧”的数据结构来保存该函数的相关信息。这些信息通常包括返回地址、局部变量和参数等。对于 ARM 架构而言,其寄存器设计使得函数调用过程更加高效且易于管理。ARM 使用特定的一组寄存器(如 `r0` 至 `r3` 表示传递给子函数的前四个参数,而剩余参数则通过堆栈传递)。此外,在每次函数调用期间会自动更新链接寄存器 (`lr`) 来存储当前 PC 寄存器值以便稍后恢复控制流[^1]。 #### 多级函数调用中的布局变化 当发生多个层次级别的连续函数调用时,每一个新层都将扩展现有调用,并分配新的空间用于存放对应上下文的信息。具体来说: - **入口阶段**: 当某个父函数 A 调用了另一个子函数 B 后,B 将接收来自 A 的输入参数并通过调整 SP(Stack Pointer) 完成自身所需内存区域初始化操作; - **内部处理阶段**: 子函数在其生命周期内可能还会进一步发起更多次更深层次的新一轮调用 C,D...直到达到最末端节点为止; - **退出阶段**: 随着各层逐步完成任务之后依次释放所占用资源直至最终回到最初起点位置即主函数处结束整个流程。 此动态增长收缩特性构成了完整的调用树形图谱形式展示出来便于后续追踪定位错误所在之处[^2]。 #### 常见调试技巧 为了有效诊断复杂场景下的异常行为或者性能瓶颈等问题,则可以采用如下几种常用手段来进行深入探究: 1. **GDB Debugger Utilization** GNU Project Debugger(GDB),作为广泛应用于Linux平台上的强大交互式源码级别调试工具之一,同样适用于ARM目标设备上进行远程连接模式下的在线实时监控活动。它允许开发者设置断点、单步执行指令甚至查看修改任意时刻内的寄存器状态及内存分布情况等等功能非常全面实用。 示例命令序列: ```bash arm-none-eabi-gdb ./example_program target remote :9999 # Connects GDB to a running OpenOCD instance listening on port 9999. break main # Sets breakpoint at 'main' function entry point. run # Starts execution from beginning until hitting first encountered breakpoints. backtrace # Prints out current call stack trace after stopping due to some event like reaching specified location or encountering errors conditions etc.. ``` 2. **Stack Trace Analysis via Backtraces** 利用之前提到过的backtrace命令可以直接获取到此刻活跃的所有未解决调用关系链条列表视图,这对于快速识别潜在风险隐患具有重要意义。另外还可以借助额外插件比如frame-filter等功能增强可读性和效率方面表现更好些. 3. **Memory Map Inspection & Variable Monitoring** 对某些特殊情况下仅依靠常规方式难以捕捉确切原因的话,则有必要深入了解底层硬件层面细节部分了。这时可以通过查阅相关手册资料明确各个关键部位实际物理地址映射规则进而针对性实施相应措施加以验证确认无误后再做决定采取行动消除影响因素达成预期效果目的[^3]. ```c++ #include <stdio.h> void third_function() { printf("This is Third Function\n"); } void second_function(){ third_function(); } int main(void){ second_function(); return 0; } ``` 上述例子展示了简单的三层嵌套调用情形,其中包含了如何利用printf语句简单打印消息辅助观察逻辑走向等内容供参考学习之用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值