You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C/C++嵌入式系统中Stack与Code内存视角的函数调用工作原理咨询

问题1 内存分区的存储介质属性

  • 易失性内存(RAM)存储分区:
    • Stack(栈):运行时动态存储函数局部变量、返回地址、寄存器上下文
    • Heap(堆):运行时动态分配的内存块
    • 可读写静态存储区:包含data段(已初始化的可读写全局/静态变量)、bss段(未初始化的可读写全局/静态变量,启动时自动清零)
  • 非易失性内存(Flash/ROM)存储分区:
    • text段(Code代码段):所有可执行的汇编指令
    • rodata段:只读静态常量,包括const修饰的全局/静态变量、字符串字面量
  • 应用执行时不会全量拷贝到RAM:绝大多数裸机场景都支持XIP(就地执行),代码段和只读常量段直接在Flash里读取执行,只有data段会在启动阶段从Flash拷贝初始值到RAM,bss段直接在RAM里清零,栈和堆是启动时在RAM里预留好地址范围,运行时直接使用。只有对性能要求极高的场景,才会手动把高频调用的代码段拷贝到RAM中运行,降低取指延迟。

问题2 函数调用时的内存操作

函数调用时完全不会拷贝汇编指令到栈中,仅会为当前函数分配对应的栈内存,用来存储当前函数的局部变量、调用方的返回地址、需要保留的寄存器上下文。函数的汇编指令始终存放在text段(Flash或RAM的代码段中),调用时CPU直接跳转到对应指令的内存地址执行即可,无需复制指令。

问题3 函数变量地址的绑定逻辑

你提到的“变量地址添加到汇编代码”的操作实际上几乎都在编译链接阶段完成,运行时不需要修改汇编代码本身,具体逻辑如下:

  • 全局/静态变量:编译阶段就会确定其固定的内存地址,链接时直接把地址硬编码到对应的汇编指令中,运行时直接读取即可。
  • 栈上局部变量:通过栈指针(SP寄存器)的偏移量寻址,编译阶段就能算出每个局部变量相对于SP的固定偏移,汇编指令中直接用SP + 偏移量的方式访问,运行时SP会随着函数的入栈出栈自动调整,自然就能匹配当前函数的栈内存地址。
  • 堆上变量:调用malloc等分配函数时会返回动态分配的内存地址,函数运行时将这个地址存在寄存器或栈上,后续直接通过该指针访问即可,不需要修改原有汇编代码。

问题4 裸机MCU的函数调用内存管理

无OS的裸机MCU中,函数调用相关的内存管理完全由编译器、链接脚本和启动代码负责,不需要OS介入:

  • 栈的大小是在链接脚本中提前配置好的,MCU上电后运行启动代码时,会直接把SP寄存器设置为栈内存的最高地址(ARM架构下栈默认向下增长),后续函数调用时CPU会通过硬件指令自动操作SP寄存器完成栈内存的分配和释放,不需要额外的管理代码。
  • 如果用到堆内存,一般是用C标准库的malloc/free实现,或者自己实现的内存分配算法,直接在链接脚本预留的堆地址范围内操作即可,同样不需要OS支持。

内容的提问来源于stack exchange,提问作者Vidit Katlana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 19:06:04