1. 内存布局
1.1 Linux C++ 内存布局示意
高地址 +---------------------------+
| 栈 (Stack) | ← 局部变量、函数参数、返回地址 |
↓ 增长 |
(向下增长)
+---------------------------+
|
|
空闲区域 |
|
+---------------------------+
| 堆 (Heap) | ← 动态分配 (new/malloc) |
↑ 增长 |
(向上增长)
+---------------------------+
| 内存映射段 (mmap) | ← 共享库、动态映射、大分配
+---------------------------+
| BSS 段 | ← 未初始化的全局/静态变量
+---------------------------+
| 数据段 (.data) | ← 已初始化的全局/静态变量 (可读写)
+---------------------------+
| 只读数据段 (.rodata) | ← 常量、字符串字面量 (只读)
+---------------------------+
| 代码段 (.text) | ← 程序指令 (只读 + 可执行)
+---------------------------+
低地址
1.2 内存布局由谁规定
链接脚本的作用:
- 内存映射:将程序逻辑段(代码/数据)映射到物理内存(FLASH/RAM)
- 地址分配:精确控制各段在内存中的位置和布局
- 符号定义:生成关键地址符号供启动文件和 C 代码使用
- 优化控制:决定哪些段保留/丢弃,影响最终固件大小
一个 ARMv7-M 架构的硬件的链接脚本如下,其内存布局与 Linux C++ 不同:
/* ========================================================================
* 1. 程序入口点
* ======================================================================== */
ENTRY(Reset_Handler)
/* ========================================================================
* 2. 定义变量栈顶 _estack - 从 RAM 顶部开始向下生长
* 计算:0x20000000 + 32KB = 0x20008000
* ======================================================================== */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* ========================================================================
* 3. 物理内存定义 - STM32G431RBT6 固定配置
* ======================================================================== */
MEMORY {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* 程序存储区 */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K /* 数据运行区 */
}
/* ========================================================================
* 4. 内存段布局,定义段映射规则
* 每个 { ... } 块是一个输出段
* 书写顺序决定了不同段在内存中的物理排列顺序
* VMA(Virtual Memory Address):程序运行时该段所在的地址
* LMA(Load Memory Address):该段在存储介质中的地址,AT 用于显示指定 LMA
* . 是当前位置计数器(location counter)
* 它的值是 当前输出段的 VMA,即程序运行时该位置的地址
* ======================================================================== */
SECTIONS {
/* --------------------------------------------------------------
* 4.1 中断向量表 - 位于 FLASH 起始地址:0x08000000
* Cortex-M4 硬件要求:前 8 字节 = [栈顶,复位地址]
* -------------------------------------------------------------- */
.isr_vector : {
. = ALIGN();
KEEP(*(.isr_vector))
KEEP(*(.vectors))
. = ALIGN();
} > FLASH
.text : {
. = ALIGN();
*(.text*)
*(.glue_7)
*(.glue_7t)
*(.eh_frame)
. = ALIGN();
_etext = .;
} > FLASH
.rodata : {
. = ALIGN();
*(.rodata*)
*(.rodata.*)
. = ALIGN();
} > FLASH
_sidata = LOADADDR(.data);
.data : {
. = ALIGN();
_sdata = .;
*(.data*)
*(.data.*)
. = ALIGN();
_edata = .;
} > RAM AT > FLASH
. = ALIGN();
.bss : {
_sbss = .;
*(.bss*)
*(.bss.*)
*(COMMON)
. = ALIGN();
_ebss = .;
} > RAM
.ARM.attributes : { *(.ARM.attributes) }
/DISCARD/ : {
*(.ARM.exidx*)
*(.ARM.extab*)
*(.init)
*(.fini)
*(.preinit_array*)
*(.init_array*)
*(.fini_array*)
*(.note.gnu.build-id)
}
}


