3. 链接脚本定制

链接脚本定制 学习卡片

任务目标

编写GNU ld链接脚本,将Bootloader与应用程序分别映射到独立Flash区域,确保两者地址空间不重叠,并为后续跳转与固件升级建立地址基础。

环境与依赖

  • ARM Cortex-M交叉工具链(arm-none-eabi-gcc / ld)
  • 目标MCU:STM32F103C8(Flash 64KB,起始0x08000000)
  • Bootloader区域:0x08000000 ~ 0x08003FFF(16KB)
  • 应用程序区域:0x08004000 ~ 0x0800FFFF(48KB)

链接脚本实现

以下链接脚本将Bootloader与应用程序分别链接到独立Flash区域。Bootloader工程使用完整脚本;应用程序工程仅需修改FLASH_ORIGIN与FLASH_LENGTH两个宏即可复用同一脚本结构。

/* memory_layout.ld —— Bootloader/应用程序共用模板 */
MEMORY
{
  /* Bootloader: 0x08000000, 16KB */
  FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 16K
  /* 应用程序: ORIGIN = 0x08004000, LENGTH = 48K */
  RAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
}

_estack = ORIGIN(RAM) + LENGTH(RAM);

SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } > FLASH

  .text :
  {
    . = ALIGN(4);
    *(.text*)
    *(.rodata*)
    . = ALIGN(4);
    _etext = .;
  } > FLASH

  _sidata = LOADADDR(.data);

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

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

关键点说明

  • 区域隔离:Bootloader链接时FLASH起始为0x08000000,应用程序链接时改为0x08004000,两者物理地址互不重叠。
  • 向量表重定位:应用程序需在启动代码中设置SCB->VTOR = 0x08004000,否则中断向量指向错误地址。
  • 数据段加载地址:AT> FLASH确保.data初始值存储在Flash,启动时由_sidata复制到RAM。

编译与链接命令

# Bootloader编译(默认链接脚本)
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -T memory_layout.ld \
  -nostdlib -Wl,--gc-sections -o boot.elf startup.c main.c

# 应用程序编译(需将脚本中FLASH ORIGIN改为0x08004000)
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -T memory_layout_app.ld \
  -nostdlib -Wl,--gc-sections -o app.elf startup.c app_main.c

# 生成二进制烧录文件
arm-none-eabi-objcopy -O binary boot.elf boot.bin
arm-none-eabi-objcopy -O binary app.elf app.bin

验证方法

  1. 链接后执行arm-none-eabi-nm boot.elf | grep _estack,确认栈顶地址为0x20005000。
  2. 执行arm-none-eabi-objdump -h boot.elf,检查.text段地址范围在0x08000000-0x08003FFF内。
  3. 应用程序链接后,.isr_vector首地址应为0x08004000,且.text段不超过0x0800FFFF。
  4. 烧录boot.bin至0x08000000、app.bin至0x08004000后,复位运行:若Bootloader能跳转至0x08004000执行应用程序,且中断响应正常,则链接脚本配置正确。

常见问题

  • 应用程序无法进入中断:检查是否已设置SCB->VTOR为应用程序起始地址。
  • 链接报region溢出:确认代码量未超过各自Flash区域大小,或调整LENGTH分配。
  • 跳转后硬件异常:检查Bootloader跳转前是否关闭全局中断、确认应用程序栈指针有效。