链接器脚本Skill linker-script

链接器脚本技能是专门为嵌入式系统开发设计的GNU链接器脚本生成与优化工具。它提供专业的内存布局定义、段放置、符号管理和高级链接场景支持,适用于微控制器(MCU)固件开发。核心功能包括内存区域定义、多镜像链接(引导加载程序+应用程序)、MPU对齐配置、覆盖段管理以及校验和放置。该技能帮助开发者优化内存使用,确保固件在Flash和RAM中的正确布局,支持安全启动和OTA更新,是嵌入式软件开发中链接阶段的关键工具。关键词:嵌入式系统,链接器脚本,GNU LD,内存布局,段放置,引导加载程序,MPU配置,固件优化,STM32,ARM Cortex-M。

嵌入式软件 1 次安装 10 次浏览 更新于 2/25/2026

name: linker-script description: GNU链接器脚本生成与优化,适用于嵌入式系统。具备内存布局定义、段放置、多镜像链接和内存保护配置的专业技能。 allowed-tools: Read, Grep, Write, Edit, Bash, Glob

链接器脚本技能

适用于嵌入式系统的GNU链接器脚本生成与优化专家技能。提供内存布局定义、段放置、符号管理和高级链接场景的深度专业知识。

概述

链接器脚本技能支持嵌入式系统的全面链接器脚本开发,包括:

  • 针对MCU目标的内存区域定义
  • 段放置和对齐配置
  • 引导加载程序/应用程序接口的符号生成
  • 多镜像链接(引导加载程序 + 应用程序)
  • 覆盖和存储体切换支持
  • 自定义段创建和管理
  • 填充模式和校验和放置
  • MPU对齐区域配置

能力

1. 内存区域定义

基于MCU规格定义内存区域:

/* 示例:STM32F407 内存布局 */
MEMORY
{
  /* Flash 内存区域 */
  FLASH_BOOT (rx)  : ORIGIN = 0x08000000, LENGTH = 32K   /* 引导加载程序 */
  FLASH_APP  (rx)  : ORIGIN = 0x08008000, LENGTH = 480K  /* 应用程序 */
  FLASH_DATA (r)   : ORIGIN = 0x08080000, LENGTH = 128K  /* 配置/OTA */

  /* RAM 区域 */
  RAM        (rwx) : ORIGIN = 0x20000000, LENGTH = 128K  /* 主 SRAM */
  CCMRAM     (rwx) : ORIGIN = 0x10000000, LENGTH = 64K   /* 核心耦合 RAM */
  BKPSRAM    (rw)  : ORIGIN = 0x40024000, LENGTH = 4K    /* 备份 SRAM */
}

2. 段放置配置

配置段放置及对齐要求:

SECTIONS
{
  /* 向量表位于 Flash 起始处 */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } > FLASH_APP

  /* 代码段 */
  .text :
  {
    . = ALIGN(4);
    *(.text)
    *(.text*)
    *(.glue_7)         /* ARM/Thumb 交互工作 */
    *(.glue_7t)
    *(.eh_frame)

    KEEP(*(.init))
    KEEP(*(.fini))

    . = ALIGN(4);
    _etext = .;
  } > FLASH_APP

  /* 只读数据 */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } > FLASH_APP
}

3. 符号生成

生成固件接口符号:

/* 引导加载程序/应用程序接口的符号 */
PROVIDE(_app_start = ORIGIN(FLASH_APP));
PROVIDE(_app_end = ORIGIN(FLASH_APP) + LENGTH(FLASH_APP));
PROVIDE(_app_checksum = _app_end - 4);

/* 栈和堆边界 */
PROVIDE(_estack = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(_Min_Heap_Size = 0x2000);  /* 8KB 堆 */
PROVIDE(_Min_Stack_Size = 0x1000); /* 4KB 栈 */

/* RAM 函数执行 */
PROVIDE(_siramfunc = LOADADDR(.ramfunc));
PROVIDE(_sramfunc = ADDR(.ramfunc));
PROVIDE(_eramfunc = ADDR(.ramfunc) + SIZEOF(.ramfunc));

4. 多镜像链接

支持引导加载程序和应用程序作为独立镜像:

/* 引导加载程序链接器脚本摘录 */
MEMORY
{
  FLASH_BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 32K
  RAM (rwx)       : ORIGIN = 0x20000000, LENGTH = 128K
}

/* 用于引导到应用程序通信的共享数据区域 */
.shared_data (NOLOAD) :
{
  . = ALIGN(4);
  _shared_data_start = .;
  KEEP(*(.shared_data))
  . = ALIGN(4);
  _shared_data_end = .;
} > RAM

/* 应用程序头位置(引导加载程序已知) */
_app_header_addr = 0x08008000;

5. MPU 区域配置

定义MPU对齐的内存区域:

/* MPU 对齐区域(2的幂次方大小,按大小对齐) */
.mpu_region_stack (NOLOAD) :
{
  . = ALIGN(1024);  /* MPU 最小区域大小 */
  _mpu_stack_start = .;
  . = . + 4096;     /* 4KB 栈区域 */
  _mpu_stack_end = .;
} > RAM

.mpu_region_heap (NOLOAD) :
{
  . = ALIGN(8192);  /* 8KB 对齐 */
  _mpu_heap_start = .;
  . = . + 8192;
  _mpu_heap_end = .;
} > RAM

6. 覆盖支持

为内存受限系统配置覆盖段:

OVERLAY : NOCROSSREFS
{
  .overlay_a { *(.overlay_a) }
  .overlay_b { *(.overlay_b) }
  .overlay_c { *(.overlay_c) }
} > RAM AT > FLASH_APP

/* 覆盖管理符号 */
_overlay_a_load = LOADADDR(.overlay_a);
_overlay_b_load = LOADADDR(.overlay_b);
_overlay_c_load = LOADADDR(.overlay_c);

7. 校验和放置

配置固件验证的校验和/CRC放置:

/* 为固件校验和预留空间 */
.checksum :
{
  . = ALIGN(4);
  _firmware_checksum = .;
  LONG(0xFFFFFFFF);  /* 占位符,构建后填充 */
  . = ALIGN(4);
} > FLASH_APP

/* 用于校验和计算的镜像长度 */
_firmware_length = _firmware_checksum - ORIGIN(FLASH_APP);

流程集成

此技能与以下流程集成:

流程 集成点
memory-architecture-planning.js 内存映射设计和验证
bootloader-implementation.js 引导/应用程序接口定义
bsp-development.js BSP 内存配置
code-size-optimization.js 段优化分析

工作流程

1. 收集 MCU 规格

# 从数据手册或参考手册中提取内存映射
# 所需关键信息:
# - Flash 基地址和大小
# - RAM 区域(主 SRAM、CCMRAM、备份 SRAM)
# - 外设内存区域
# - MPU 区域要求

2. 定义内存需求

## 内存需求分析

| 组件 | Flash | RAM | 备注 |
|-----------|-------|-----|-------|
| 引导加载程序 | 32K | 8K | 固定位置 |
| 应用程序 | 480K | 96K | 主固件 |
| 配置数据 | 8K | - | 非易失性设置 |
| OTA 暂存 | 120K | - | A/B 更新支持 |

总 Flash: 640K / 1024K (62.5% 已使用)
总 RAM: 104K / 128K (81.3% 已使用)

3. 生成链接器脚本

该技能根据需求生成完整的链接器脚本:

# 输出文件:
# - memory.ld       - 内存区域定义(由主脚本包含)
# - sections.ld     - 段定义(由主脚本包含)
# - application.ld  - 主应用程序链接器脚本
# - bootloader.ld   - 引导加载程序链接器脚本(如需要)

4. 验证内存使用

# 分析二进制大小
arm-none-eabi-size firmware.elf

# 详细映射文件分析
arm-none-eabi-nm -S --size-sort firmware.elf

# 生成内存使用报告
python scripts/analyze_map.py build/firmware.map

输出模式

{
  "linkerScript": {
    "mainScript": "application.ld",
    "includes": ["memory.ld", "sections.ld"],
    "bootloaderScript": "bootloader.ld"
  },
  "memoryMap": {
    "flash": {
      "total": 1048576,
      "regions": [
        { "name": "FLASH_BOOT", "origin": "0x08000000", "length": 32768 },
        { "name": "FLASH_APP", "origin": "0x08008000", "length": 491520 }
      ]
    },
    "ram": {
      "total": 131072,
      "regions": [
        { "name": "RAM", "origin": "0x20000000", "length": 131072 }
      ]
    }
  },
  "symbols": {
    "exportedToBootloader": ["_app_start", "_app_end", "_app_checksum"],
    "importedFromBootloader": ["_shared_data"],
    "stackHeap": ["_estack", "_Min_Heap_Size", "_Min_Stack_Size"]
  },
  "validation": {
    "flashUtilization": 0.625,
    "ramUtilization": 0.813,
    "mpuCompatible": true,
    "warnings": []
  },
  "artifacts": [
    "application.ld",
    "bootloader.ld",
    "memory.ld",
    "sections.ld",
    "memory-map.md"
  ]
}

常见模式

RAM 函数(从 RAM 执行)

/* 复制到 RAM 执行的函数(例如,Flash 编程) */
.ramfunc :
{
  . = ALIGN(4);
  _sramfunc = .;
  *(.ramfunc)
  *(.ramfunc*)
  . = ALIGN(4);
  _eramfunc = .;
} > RAM AT > FLASH_APP

_siramfunc = LOADADDR(.ramfunc);

初始化数据(.data 段)

.data :
{
  . = ALIGN(4);
  _sdata = .;
  *(.data)
  *(.data*)
  . = ALIGN(4);
  _edata = .;
} > RAM AT > FLASH_APP

_sidata = LOADADDR(.data);

零初始化数据(.bss 段)

.bss (NOLOAD) :
{
  . = ALIGN(4);
  _sbss = .;
  __bss_start__ = _sbss;
  *(.bss)
  *(.bss*)
  *(COMMON)
  . = ALIGN(4);
  _ebss = .;
  __bss_end__ = _ebss;
} > RAM

栈和堆

/* 用户堆和栈 */
._user_heap_stack (NOLOAD) :
{
  . = ALIGN(8);
  PROVIDE(end = .);
  PROVIDE(_end = .);
  . = . + _Min_Heap_Size;
  . = . + _Min_Stack_Size;
  . = ALIGN(8);
} > RAM

/* 验证有足够空间 */
ASSERT((_estack - _ebss) >= (_Min_Heap_Size + _Min_Stack_Size),
       "堆和栈的 RAM 不足")

最佳实践

内存对齐

  • 将向量表对齐到 2 的幂次方(通常为 256 或 512 字节)
  • 将代码段对齐到 4 字节(针对 ARM)
  • 将 MPU 区域对齐到其大小(2 的幂次方)
  • 将 DMA 缓冲区对齐到缓存行大小

段组织

  • 将中断向量表保持在固定位置
  • 将频繁执行的代码放在更快的内存中
  • 将相关函数分组以最小化缓存未命中
  • 对可能被垃圾回收的段使用 KEEP()

安全性

  • 添加 ASSERT 语句以捕获内存溢出
  • 为运行时栈检查定义符号
  • 为校验和/签名预留空间
  • 记录所有魔术数字

参考资料

另请参阅

  • memory-architecture-planning.js - 内存规划流程
  • bootloader-implementation.js - 引导加载程序开发
  • SK-010: 内存分析技能
  • AG-001: 固件架构师代理