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

STM32F103栈指针(sp)工作原理及地址配置疑问

为什么MCU从Flash执行代码,栈指针指向RAM却能正常运行?

核心原理:Flash与RAM的功能分工

MCU的存储区域按功能明确划分:

  • Flash(0x08000000起始):属于只读存储区(仅烧写时可写,运行时只读),专门用来存放程序指令、常量数据——硬件设计为复位后从Flash加载执行指令,这就是程序从这里启动的原因。
  • RAM(0x20000000起始):是可快速读写的随机存取区,用于存储运行时的变量、栈、堆等需要动态修改的数据。栈需要频繁执行压栈/出栈操作(存储临时数据、函数返回地址等),必须放在可读写的RAM中,Flash的只读特性完全无法满足这个需求。

复位流程与栈指针的初始化

针对ST主流的Cortex-M架构:

  1. 复位后硬件自动完成第一步:从Flash向量表的第一个字(0x08000000地址)读取栈顶地址(即链接脚本里的_estack),加载到SP寄存器。
  2. 接着从向量表第二个字读取reset_handler的地址,跳转到该函数执行。

你提供的汇编代码里在reset_handler中再次设置SP,属于冗余但安全的操作——和硬件自动加载的地址完全一致,不会产生冲突,只是为了明确展示栈初始化的步骤。

_estack设为RAM末尾的原因

链接脚本中RAM长度为20K(0x5000字节),起始地址0x20000000,因此末尾地址是0x20000000 + 0x5000 = 0x20005000:

  • Cortex-M的栈是向下生长的:压栈时SP值递减,从RAM末尾向起始地址方向使用空间。
  • 将栈顶设为RAM末尾,能最大化利用RAM空间,避免栈与全局变量、静态变量等其他RAM区域重叠。

代码片段细节说明

链接脚本中的_estack

_estack = 0x20005000;

MEMORY
{
    FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 64K
    RAM (rxw)       : ORIGIN = 0x20000000, LENGTH = 20K
}

_estack是链接器定义的符号,用来标记栈顶地址,会被写入Flash向量表的第一个位置,同时供启动代码引用。

汇编中的SP设置

.type reset_handler, %function
reset_handler:
    LDR     r0, =_estack
    MOV     sp, r0

这行代码显式初始化SP,虽然硬件已经自动完成,但保留它的好处包括:

  • 兼容非标准启动流程
  • 让新手直观理解栈的初始化逻辑
  • 后续修改栈顶地址时,只需调整链接脚本的_estack即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:43:21