函数调用时,返回地址和局部变量都存“栈”里

你有没有想过一个问题:main函数调用func,func里调用sub。sub执行完,怎么回到func刚才的位置?func执行完,怎么回到main刚才的位置?**答案是:栈。**每次函数调用,CPU把"怎么回来"的地址(LR)和局部变量都塞进一块叫"栈"的内存里。函数返回时,再从栈里弹出来。这就是函数能够"嵌套调用、正确返回"的秘密。

那个"LR"寄存器的角色 ARM32有一个专门的寄存器叫LR(链接寄存器,R14)。

调用函数时:

main: BL func ; 跳转前,硬件自动把返回地址存入LR

BL指令执行时,CPU把BL的下一条指令地址(main里func后面的代码)存入LR。

然后跳转到func函数。func执行完,执行BX LR------跳转到LR指向的地址,回到main继续执行。

那个"嵌套"的问题, 如果func里又调用了sub:func中的BL sub会覆盖LR。问题:sub执行完后,LR存的是sub的返回地址(func里sub后面的代码)。那func自己的返回地址(main里的地址)怎么办?必须存到栈里。

那个"压栈"的时机, 编译器会自动在每个函数开头插入PUSH指令,把LR压入栈。

func:

PUSH {LR} ; 保存返回地址

BL sub ; 调用sub

POP {PC} ; 恢复LR到PC,返回

嵌套多层调用,返回地址就被一层层压在栈里。后调用的先返回------栈的特性。

那个"局部变量"也存栈里函数内部的局部变量,也分配在栈里。

void func(void) {

int a = 1; // 栈上分配4字节

int b = 2; // 栈上分配4字节

int c = a + b; // 栈上的变量参与运算

}

编译后,函数开头会SP减去若干字节 ,为局部变量腾出空间(PUSH或SUB SP)。函数返回前,SP加回相同的字节数 ,释放栈空间。局部变量的生命周期 = 函数的生命周期。

**那个"栈帧"的概念,**每次函数调用,都在栈上开辟一块区域:

  • 返回地址(LR)
  • 局部变量
  • 保存的寄存器(R4-R11等)

这块区域叫栈帧 (Stack Frame)。多层调用,栈帧一个叠一个。那个"溢出"的风险, 栈空间不是无限的。如果函数嵌套太深,或者局部变量太大,栈可能越界。栈溢出后,数据覆盖了其他内存区域(如全局变量、堆)。Bug诡异,难以排查。

这个故事的启示, 为什么函数能正确返回?因为栈记住了"来时的路" 。LR只能存一个返回地址,栈可以存无数个。函数嵌套多深,栈就能记多远。

写在最后, 下次你写函数,别只管业务逻辑。想想背后那个叫"栈"的东西。它在默默帮你记住"怎么回来"。栈,是函数的"记忆体"。


(本文灵感源于于振南《新概念ARM32单片机》教程第5.3节"程序现场的存储与恢复:栈与MSP",感谢作者将函数调用的底层机制讲得如此通透。)


如果您觉得这个故事对您有启发,欢迎点赞、转发,让更多工程师看到这个藏在函数调用背后的"栈"智慧。

相关推荐
ye150127774555 小时前
220V降12V降24V风扇驱动WT5112
单片机·嵌入式硬件·其他·硬件工程
-Springer-6 小时前
STM32 学习 —— 个人学习笔记11-2(SPI 通信外设 & 硬件 SPI 读写 W25Q64)
笔记·stm32·学习
dqsh066 小时前
STM32和STM32CubeMX实现遥控器控制, 保姆级教程
stm32·单片机·嵌入式硬件·机器人·遥控器
llilian_166 小时前
晶振测量仪 晶振频率测试仪器的多领域应用解析 晶振频率测试仪器
功能测试·单片机·嵌入式硬件·测试工具·51单片机
kaikaile19956 小时前
基于STM32F103的BMS通信控制
stm32·单片机·嵌入式硬件
天天爱吃肉82186 小时前
笔记:同步电机调试时电角度校正方法说明
大数据·人工智能·笔记·功能测试·嵌入式硬件·汽车
国科安芯6 小时前
空间激光通信系统中抗辐射 MCU 芯片应用研究
单片机·嵌入式硬件·架构·risc-v·安全性测试
Deitymoon6 小时前
STM32——外部中断
stm32·单片机·嵌入式硬件
踏着七彩祥云的小丑6 小时前
嵌入式——认识电子元器件——继电器系列
单片机·嵌入式硬件