You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32中GNU linker生成段(program header)地址与执行代码地址不一致问题

STM32 程序地址偏移与烧录镜像问题

问题背景

为实现Bootloader功能,尝试将STM32可执行代码生成在默认地址0x8000000以外的位置,使用STM32CubeIDE 1.11.2版本,工具链为GCC 10.3.1(GNU Tools for STM32 10.3-2021.10.20211105-1100)。

修改链接脚本中的FLASH起始地址为0x8003800:

/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 144K
  FLASH    (rx)    : ORIGIN = 0x8003800,   LENGTH = 512K
}

编译正常,但通过arm-none-eabi-objdump查看发现:所有符号和执行代码地址正确,但ELF文件的program header地址仍为0x8000000,而非0x8003800。该program header的P_OFFSET=0、P_ADDR=0x8000000、P_FILESZ=0x000039c4,会导致烧录工具将ELF文件偏移0处的内容(含ELF头)烧录到STM32的0x8000000地址,覆盖原有Bootloader,同时0x8003800地址前会被写入无效内容。

问题

  1. 上述操作是否存在错误?
  2. 如何生成可烧录到指定地址且不会覆盖已有镜像(如Bootloader)的纯二进制镜像?

解答

1. 操作中的错误点

  • 链接脚本修改不完整:仅修改MEMORY区块的FLASH起始地址是不够的,还需要检查链接脚本中SECTIONS部分的配置,确保*.text、.rodata等代码/只读数据段的起始地址*与MEMORY中定义的0x8003800对齐。部分默认链接脚本会在SECTIONS里硬编码FLASH起始地址,而非引用MEMORY的定义,这会导致program header仍使用旧地址。
  • 未明确指定程序段加载地址:GCC链接时,若未强制指定程序段的加载基地址,可能会沿用默认的0x8000000。需要确保链接脚本中SECTIONS里的.text等段的AT属性(加载地址)与运行地址一致,或者通过链接参数-Ttext=0x8003800强制指定。

2. 生成指定地址的纯二进制镜像方法

方法一:使用arm-none-eabi-objcopy手动生成

编译完成后,通过以下命令从ELF文件提取有效代码段,生成纯二进制镜像:

arm-none-eabi-objcopy -O binary -j .text -j .rodata -j .data your_project.elf your_project.bin
  • -O binary:指定输出格式为纯二进制
  • -j:仅保留指定的有效段(可根据项目需求添加/删除段,比如.bss无需包含,会在启动时初始化)
  • 生成的.bin文件可直接通过烧录工具指定目标地址0x8003800烧录,不会覆盖0x8000000处的Bootloader。

方法二:在STM32CubeIDE中配置自动生成

  1. 打开项目属性,进入C/C++ Build > Settings > Tool Settings > MCU Post build outputs
  2. 勾选Convert to binary file using objcopy
  3. 在objcopy flags中添加参数:-O binary -j .text -j .rodata -j .data
  4. 重新编译后,IDE会自动在输出目录生成对应的.bin文件,烧录时指定目标地址为0x8003800即可。

方法三:修正链接脚本确保ELF程序段地址正确

修改链接脚本的SECTIONS部分,确保所有FLASH相关段的起始地址指向0x8003800,示例:

SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* 中断向量表 */
    . = ALIGN(4);
  } >FLASH

  .text :
  {
    . = ALIGN(4);
    *(.text)           /* 代码段 */
    *(.text*)          /* 扩展代码段 */
    *(.glue_7)         /* ARM与Thumb代码衔接段 */
    *(.glue_7t)        /* Thumb与ARM代码衔接段 */
    *(.eh_frame)

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

    . = ALIGN(4);
    _etext = .;        /* 代码段结束标记 */
  } >FLASH

  /* .rodata、.data等其他FLASH相关段同理,确保都关联到FLASH区块 */
}

修改后重新编译,ELF的program header地址会与MEMORY定义一致,但仍建议使用纯二进制镜像烧录,避免ELF头带来的潜在干扰。


内容的提问来源于stack exchange,提问作者yo3hcv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 23:03:29