
文章目录STM32F103C8T6内存分配与堆栈memory mapAliased to Flash or system memory depending on BOOT pinsFlash MemorySystem MemoryOption Bytes (0x1FF800~0x1FF80F)SRAM (0x20000000)Flash1. 中断向量表 (Interrupt Vector Table)2. 代码段 (.text / Code)3. 只读数据段 (.rodata / ReadOnly Data)4. 初始化数据模板 (.data Load Address)SRAM1. .data 段 (Initialized Data)2. .bss 段 (Block Started by Symbol)3. .heap 段 (堆)4. .stack 段 (主栈 / Main Stack)STM32F103C8T6内存分配与堆栈memory map在STM32F103C8T6数据手册中我们可以找到他的memory map如上图图中标注的有三块内容Cortex-M3 Internal PeripheralsCortex-M3内核自带的功能模块位于内存映射中的私有外设总线PPB, Private Peripheral Bus区域常见的 Cortex-M3 Internal Peripherals 包括模块缩写功能简述Nested Vectored Interrupt ControllerNVIC管理中断优先级、嵌套、使能/禁用System Control BlockSCB控制系统行为如复位、睡眠模式、异常处理SysTick TimerSysTick24 位递减定时器常用于 RTOS 时间片或延时Data Watchpoint and Trace UnitDWT数据观察点、性能计数、调试跟踪Instrumentation Trace MacrocellITM输出调试信息到 SWO 引脚如 printf 到 IDEFlash Patch and Breakpoint UnitFPB支持硬件断点和代码补丁Memory Protection UnitMPU可选内存保护防止非法访问Peripherals外设没有独立的地址空间而是被映射到内存地址空间中STM32F103 的外设非常丰富包括GPIO、I2C、SPI等最后一块是我们要特别关注的我们展开来讲‘Aliased to Flash or system memory depending on BOOT pins含义地址0x00000000是一个“虚拟入口”它不直接对应物理存储器而是根据BOOT0 和 BOOT1 引脚的电平动态映射到主闪存Flash memory→ 正常运行用户程序系统存储器System memory→ 进入官方 Bootloader通过串口下载程序某些型号还支持映射到 SRAM为什么这样设计符合 ARM Cortex-M3 规范复位后必须从0x00000000取向量表提供灵活性无需修改硬件即可切换启动源支持恢复机制即使 Flash 损坏仍可通过 System Memory 重新烧录BOOT1BOOT0启动目标应用场景X0Main Flash正常运行01System MemoryISP 串口下载11Embedded SRAM调试/测试 RAM 中代码Flash Memory存放你的编译后的程序代码、常量数据断电不丢失C8T6 型号通常为 64KB所以有效范围是0x08000000 ~ 0x0800FFFF图中有误System Memory出厂预置的只读存储器包含 ST 官方的 Bootloader不可被用户程序修改当 BOOT01, BOOT10 时CPU 从这里启动等待通过 USART1 接收新固件是实现“一键串口下载”的基础Option Bytes (0x1FF800~0x1FF80F)特殊配置区域用于设置读保护级别RDP写保护扇区看门狗使能启动模式默认值VDDA 监控等需要通过特殊命令如 OB_Launch才能生效一般通过 STM32CubeProgrammer 或 J-Link 工具配置SRAM (0x20000000)虽然图中左侧单独画出但在完整内存映射中SRAM 位于0x20000000 ~ 0x20004FFF20KB for C8T6用于存放变量、堆栈、动态数据断电丢失只要有电数据就不会丢也可作为启动目标BOOT01, BOOT11常用于快速调试或 OTA 升级前的临时运行Flash1. 中断向量表 (Interrupt Vector Table)地址范围0x08000000~0x080000FF(通常占用前 256 字节或更多取决于中断数量)内容初始 MSP 值(0x08000000)栈顶指针初始值复位向量(0x08000004)Reset_Handler函数地址中断服务程序入口依次存放 NMI、HardFault、以及所有外设中断如 EXTI、TIM、USART 等的处理函数地址特点这是芯片启动时硬件首先读取的区域必须位于 Flash 的最起始位置地址内容含义作用0x08000000初始 MSP 值主堆栈指针 (Main Stack Pointer) 的初始值复位后CPU 首先从该地址读取一个 32 位数值并将其加载到 MSP 寄存器。这决定了系统启动时栈顶的位置通常指向 RAM 的末尾。0x08000004复位向量复位中断服务程序 (Reset_Handler) 的地址CPU 接着从该地址读取一个 32 位数值并将其加载到 PC (程序计数器)。CPU 随后跳转到这个地址开始执行第一条指令通常是SystemInit和main函数。2. 代码段 (.text / Code)地址范围紧接向量表之后通常从0x08000100或0x08000200开始占据 Flash 的绝大部分内容用户程序指令main()函数、各类子函数、ISR 的具体实现代码启动代码startup_stm32f10x_md.s中的复位处理逻辑、系统初始化代码 (SystemInit)、C 库初始化代码如数据段拷贝、BSS 段清零只读常量被const修饰的全局变量和静态变量如果编译器优化将它们放在.rodata并合并到.text中特点这是程序的主体部分CPU 从这里取指执行。3. 只读数据段 (.rodata / ReadOnly Data)地址范围通常紧跟在.text段之后或者合并在一起内容字符串常量如printf(Hello)中的 “Hello”查找表如const uint8_t lookup_table[] {...}其他常量所有编译期确定的只读数据注意在某些链接脚本配置中.rodata会被合并到.text段中物理上不分家但在逻辑概念上是分开的4. 初始化数据模板 (.data Load Address)地址范围位于.rodata之后Flash 的高地址部分具体位置取决于链接脚本。内容已初始化全局/静态变量的初值关键机制这些变量在程序运行时是存放在SRAM中的但在 Flash 中必须保存一份“副本”模板启动过程在Reset_Handler中启动代码会将这部分数据从 Flash拷贝到 SRAM 的.data区域特点如果不拷贝SRAM 中的变量将无法获得初始值因为 SRAM 掉电丢失且上电随机SRAM1..data段 (Initialized Data)位置SRAM 的最低地址部分紧接0x20000000内容所有显式初始化的全局变量和静态变量例如int g_val 10;或static uint8_t flag 1;来源这些变量的初值存放在 Flash 的.data加载区。系统启动时Reset_Handler中C 运行时库会将它们从 Flash拷贝到 SRAM 的这个位置大小取决于你定义了多少带初值的全局/静态变量2..bss段 (Block Started by Symbol)位置紧接在.data段之后内容所有未初始化或显式初始化为 0 的全局变量和静态变量例如int g_zero;或static int g_null 0;特点它们不占用 Flash 空间因为初值都是 0没必要存系统启动时C 运行时库会将这块内存区域全部清零大小取决于未初始化变量的总大小注意我们给FreeRTOS分配的内存就是在.bss段3..heap段 (堆)位置紧接在.bss段之后向高地址方向增长内容用于动态内存分配当你调用malloc(),calloc(),realloc()时内存从这里分配调用free()时内存被释放回这里大小在链接脚本.ld 文件中定义例如_Min_Heap_Size。如果没定义默认可能很小或直到碰到栈风险如果堆增长过大可能会侵入栈空间导致堆栈碰撞 (Heap-Stack Collision)引发难以调试的系统崩溃4..stack段 (主栈 / Main Stack)位置位于 SRAM 的最高地址附近向低地址方向增长内容局部变量函数内部定义的int a;函数参数传递给函数的参数返回地址函数调用后返回的位置寄存器上下文中断发生时CPU 自动压栈保存的寄存器状态 (R0-R3, R12, LR, PC, xPSR)初始状态Flash 的第一个字 (0x08000000) 存储的值就是栈的初始栈顶指针 (MSP)通常设置为 SRAM 的末尾如0x20005000随着函数调用和中断发生SP 指针减小栈“向下”生长重要性如果栈溢出Stack Overflow会覆盖堆数据或.bss数据导致程序跑飞或进入 HardFault