c
Stack_Size EQU 0x00001500
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000300
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
详细说明
第1行:定义栈大小
armasm
Stack_Size EQU 0x00001500
EQU: 等值伪指令,类似于C语言的 #define
Stack_Size: 符号名称,将被赋值为后面的值
0x00001500: 十六进制数,转换为十进制是 5376 字节(5.25KB)
作用: 定义了栈的总大小为 5376 字节
第2-4行:定义栈内存区域
armasm
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
第2行:
AREA: 定义一个新的段(section)
STACK: 段名,告诉链接器这是栈段
NOINIT: 该段不需要初始化,复位后内容不确定(可以提高启动速度)
READWRITE: 可读可写
ALIGN=3: 2³ = 8 字节对齐,满足 Cortex-M 处理器的要求
第3行:
Stack_Mem: 栈内存起始地址的标签
SPACE: 保留指定大小的内存空间
Stack_Size: 使用前面定义的 0x00001500 字节
第4行:
__initial_sp: 这是一个特殊标签,表示栈顶地址
由于 ARM Cortex-M 使用满递减栈,这个地址实际上是栈的结束地址
第5-8行:注释和堆配置
armasm
; Heap Configuration
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
这是 IDE/配置工具自动生成的注释
通常用于配置界面中显示帮助信息
表明下面的堆大小可以在配置工具中修改
第9行:定义堆大小
armasm
Heap_Size EQU 0x00000300
与栈大小定义类似
0x00000300: 十六进制,转换为十进制是 768 字节
定义了堆的总大小为 768 字节
第10-13行:定义堆内存区域
armasm
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
第10行:
与栈区域类似,但段名为 HEAP
告诉链接器这是堆段
具有相同的属性:NOINIT, READWRITE, ALIGN=3
第11行:
__heap_base: 特殊标签,表示堆的起始地址
C 标准库(如 malloc/free)会使用这个符号
第12行:
Heap_Mem: 堆内存起始地址的标签
SPACE: 保留堆大小的内存空间
Heap_Size: 使用前面定义的 0x00000300 字节
第13行:
__heap_limit: 特殊标签,表示堆的结束地址
C 标准库使用这个符号来检查堆的边界
栈和堆的方向
栈: 从高地址向低地址增长(满递减栈)
堆: 从低地址向高地址增长
特殊符号的作用
__initial_sp: 处理器复位后,SP(栈指针)的初始值
__heap_base 和 __heap_limit: 被 C 运行时库用于内存分配
实际使用
这些定义通常在启动文件(startup.s)中
链接器脚本会使用这些段名来定位栈和堆的位置
在分散加载文件中,这些段通常放在 RAM 的末尾和开头
堆和栈链接计算规则
链接器的计算过程
链接器按照以下顺序分配内存:
RW数据(已初始化变量)
ZI数据(零初始化变量,包括.bss和用户变量)
堆(Heap)
栈(Stack)
验证链接规则:
通过查看四部分数据地址可以证明链接计算规则
