沧州散热器测评:河北卓兴质量优但创新稍慢,综合得分领先其他
2026/5/16 6:23:04
链接脚本是嵌入式开发中链接器的核心配置文件,相当于链接器的“内存布局施工图纸”,核心作用是告诉链接器如何将编译生成的各代码段、数据段,精准映射到芯片的指定内存地址。
/* 1. 定义内存区域:Flash(只读)、RAM(可读写) */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } /* 2. 段映射规则 */ SECTIONS { /* 中断向量表:强制放Flash起始地址,防止优化 */ .isr_vector : { KEEP(*(.isr_vector)) } >FLASH /* 代码段:存放程序指令,定义代码结束符号 */ .text : { *(.text .text*) _etext = .; } >FLASH /* 只读数据段:存放常量 */ .rodata : { *(.rodata) } >FLASH /* 已初始化数据段:LMA在Flash,VMA在RAM */ .data : AT(ADDR(.rodata) + SIZEOF(.rodata)) { _sdata = .; *(.data); _edata = .; } >RAM /* 未初始化数据段(BSS):启动时清零 */ .bss : { _sbss = .; *(.bss) *(COMMON); _ebss = .; } >RAM /* 堆栈定义:RAM末尾分配栈,BSS结束后分配堆 */ _heap_start = _ebss; _heap_end = ORIGIN(RAM) + LENGTH(RAM) - 1; _stack_start = _heap_end; }链接器按脚本生成ELF文件段头表:
链接脚本的优化本质是精细化管理内存资源:将不同特性的代码/数据放到最适合的存储区域,减少访存开销、避免内存碎片、提升执行效率,同时规避硬件限制。
嵌入式芯片中,RAM访问速度远快于Flash,可将频繁调用的函数/关键数据从Flash移到RAM,降低执行耗时。
示例:STM32中将高频函数放入RAM
/* 1. 先定义内存区域(基础) */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } /* 2. 自定义段:专门存放要放到RAM的函数 */ SECTIONS { /* 高频函数段:.fast_code 是自定义段名 */ .fast_code : { /* 匹配指定文件中的所有函数(如fast_functions.o) */ *(.fast_code) fast_functions.o(.text*) /* 直接指定文件的所有.text段 */ } >RAM /* 运行地址(VMA)在RAM */ AT>FLASH /* 加载地址(LMA)在Flash,启动时自动复制到RAM */ /* 保留原有基础段(省略重复部分,仅展示核心) */ .isr_vector : { KEEP(*(.isr_vector)) } >FLASH .text : { *(.text .text*) } >FLASH /* ... 其他段(.rodata/.data/.bss)保持不变 */ }代码中配合使用(C语言):
// 用__attribute__将函数指定到自定义的.fast_code段 __attribute__((section(".fast_code"))) void high_freq_function(void) { // 频繁执行的核心逻辑 }默认链接脚本可能将所有数据段合并,导致RAM碎片化;可通过拆分段,将小数据集中存放,或限制堆/栈大小,避免内存浪费。
示例:拆分BSS段,分离大数组与普通变量
SECTIONS { /* 普通BSS段:存放小变量,优先分配 */ .bss_small : { _sbss_small = .; *(.bss_small) /* 自定义段,存放小变量 */ _ebss_small = .; } >RAM /* 大数组BSS段:单独分配,避免碎片化 */ .bss_large : { _sbss_large = .; *(.bss_large) /* 自定义段,存放大数组 */ _ebss_large = .; } >RAM /* 原有普通BSS段:存放未指定的变量 */ .bss : { _sbss = .; *(.bss) *(COMMON); _ebss = .; } >RAM /* 限制堆大小:避免堆占用过多RAM */ _heap_start = _ebss; _heap_end = _heap_start + 16K; /* 堆大小固定为16K */ _stack_start = ORIGIN(RAM) + LENGTH(RAM) - 1; /* 栈用剩余RAM */ }KEEP()防止被优化,保证中断正常响应;示例:保护中断向量表+外设地址映射
SECTIONS { /* 中断向量表:强制放Flash起始,KEEP防止优化 */ .isr_vector : { KEEP(*(.isr_vector)) /* 核心:防止链接时被GC(垃圾回收) */ } >FLASH AT>FLASH /* 外设寄存器段:映射到GPIOA寄存器基地址0x40010800 */ .periph_gpioa : { *(.periph_gpioa) } >RAM AT>0x40010800 /* 直接指定加载地址为外设寄存器地址 */ }将Bootloader和应用程序(APP)分配到Flash不同区域,防止互相覆盖,同时支持APP独立升级。
示例:Flash分区规划
MEMORY { /* Bootloader:前32K Flash */ BOOT_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* APP程序:剩余480K Flash */ APP_FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* RAM:共享使用 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } SECTIONS { /* Bootloader代码段:仅用BOOT_FLASH */ .boot_text : { bootloader.o(.text*) } >BOOT_FLASH /* APP代码段:仅用APP_FLASH */ .app_text : { app_main.o(.text*) } >APP_FLASH /* 数据段共享RAM */ .data : { _sdata = .; *(.data); _edata = .; } >RAM AT>APP_FLASH }ALIGN(4)保证对齐,避免访存错误:.fast_code : { ALIGN(4); /* 4字节对齐 */ *(.fast_code); } >RAM AT>FLASHKEEP()保护关键段;