1. 编译阶段:分类与生成
- 输入:源代码(C/C++/汇编等)
- 处理 :编译器根据变量/函数的属性(是否初始化、是否用
__attribute__((section("name")))修饰等)将内容归类到不同的段(Section)。 - 输出 :目标文件(
.o或.obj),其中每个段内仅包含相对于该段起始的偏移地址 ,最终运行时地址尚未确定。
2. 链接阶段:定位与整合
- 输入 :多个目标文件 + 链接脚本 (
.ld) - 处理:
-
- 收集所有目标文件中的同名段,合并成一个大的段。
- 按照链接脚本的规则,为每个段分配最终的运行时地址 (在裸机/固件环境下即物理地址)。
- 修正代码中的地址引用(重定位),生成可执行映像。
- 输出 :可执行映像文件(如
.elf、.bin或.hex)
3. 自定义段的工作机制
-
在代码中定义 :使用编译器扩展(如 GCC 的
__attribute__((section("my_section"))))将特定变量或函数放入自定义段。 -
在链接脚本中声明:必须显式描述如何处理该自定义段,例如:
my_section : { *(.my_section) } > RAM
否则,该段会被链接器丢弃,不会出现在最终内存映像中。
4. 核心总结
编译负责"分类",链接负责"定位"
链接脚本是连接编译输出与最终内存布局的蓝图 。
自定义段通过编译属性生成,再通过链接脚本精确落地到特定内存地址,这是固件开发中实现精细内存控制(如调试缓冲、DMA 区域、保留内存)的根本方法。
注:上述机制适用于裸机/固件环境(无操作系统加载器介入)。在有操作系统的环境中,链接脚本生成的为相对地址,最终由操作系统加载器完成虚拟地址映射。