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
验证方法
- 链接后执行
arm-none-eabi-nm boot.elf | grep _estack,确认栈顶地址为0x20005000。 - 执行
arm-none-eabi-objdump -h boot.elf,检查.text段地址范围在0x08000000-0x08003FFF内。 - 应用程序链接后,
.isr_vector首地址应为0x08004000,且.text段不超过0x0800FFFF。 - 烧录boot.bin至0x08000000、app.bin至0x08004000后,复位运行:若Bootloader能跳转至0x08004000执行应用程序,且中断响应正常,则链接脚本配置正确。
常见问题
- 应用程序无法进入中断:检查是否已设置
SCB->VTOR为应用程序起始地址。 - 链接报region溢出:确认代码量未超过各自Flash区域大小,或调整
LENGTH分配。 - 跳转后硬件异常:检查Bootloader跳转前是否关闭全局中断、确认应用程序栈指针有效。