STM32启动流程的隐秘角落:链接脚本与内存布局的深度对话
对于许多嵌入式开发者而言,STM32的启动流程往往被视为一个"黑盒"——我们知道它存在,却很少深入探究其内部机制。直到某天,你的程序因为内存溢出而崩溃,或者某个全局变量莫名其妙地丢失了初始值,你才会意识到理解这个过程的必要性。链接脚本(.ld文件)与启动文件的精妙配合,构成了STM32从复位到main()函数执行的核心骨架,而这正是我们今天要深入探讨的主题。
1. 内存布局的艺术:链接脚本的底层逻辑
链接脚本(Linker Script)是嵌入式开发中最容易被忽视却至关重要的组成部分。它不仅仅是告诉链接器如何安排代码和数据的位置,更是定义了整个程序在内存中的生存方式。
当我们编译一个STM32项目时,编译器会生成多个目标文件,每个文件包含代码(.text)、已初始化数据(.data)、未初始化数据(.bss)等段。链接器的任务就是将这些分散的段按照特定规则组合起来,形成一个完整的可执行文件。而这个"规则"正是由链接脚本定义的。
一个典型的STM32链接脚本包含以下关键元素:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector))
. = ALIGN(4);
} > FLASH
.text :
{
*(.text)
*(.text*)
} > FLASH
.data :
{
_sdata = .;
*(.data)
*(.data*)
_edata = .;
} > RAM AT > FLASH
.bss :
{
_sbss = .;
*(.bss)
*(.bss*)
_ebss = .;
} > RAM
}
这个脚本定义了FLASH和RAM的物理地址和大小,然后指定了各个段应该如何放置。特别注意.data段的定义:它被标记为> RAM AT > FLASH,这意味着.data段在运行时位于RAM中,但其初始值存储在FLASH中。这种设计直接影响了启动流程中数据搬运的过程。
关键符号解析:
_estack:栈顶指针,定义了主堆栈的结束位置_sdata/_edata:已初始化数据段的起始和结束地址_sbss/_ebss:未初始化数据段的


被折叠的 条评论
为什么被折叠?



