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

链接器脚本:如何将重定位段标记为占用两个内存区域的空间

解决嵌入式链接器脚本中重定位段同时计入ROM和RAM占用的问题

我来帮你搞定这个问题——在GNU链接器(ld)脚本中,要让那些通过AT特性重定位的段(加载在FLASH、运行在RAM)同时计入两个内存区域的占用,核心是让链接器同时统计该段在**加载区域(FLASH)和运行区域(RAM)**的空间使用。默认情况下链接器只会统计段运行地址所在区域的占用,所以我们需要显式地让加载区域也统计这段空间。

步骤1:正确定义内存区域

首先确保你已经在脚本顶部定义了FLASH和RAM的内存区域,比如:

MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K  /* 替换为你的设备FLASH参数 */
  RAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K   /* 替换为你的设备RAM参数 */
}

步骤2:定义重定位段并关联双区域

接下来,定义你的重定位段(比如.text_ram,存放需要在RAM运行的代码),同时在FLASH区域中添加一个占位符段,大小与重定位段完全一致,以此让链接器统计FLASH的占用:

SECTIONS
{
  /* 常规FLASH段:存放不需要重定位的代码、只读数据 */
  .text :
  {
    __TEXT_START__ = .;
    *(.text)
    *(.text.*)
    __TEXT_END__ = .;
  } >FLASH

  /* -------------------------- 核心部分 -------------------------- */
  /* 重定位段:运行地址在RAM,加载地址通过AT指定到FLASH */
  .text_ram :
  {
    . = ALIGN(4);
    __TEXT_RAM_RUN_START__ = .;  /* RAM中的运行起始地址 */
    *(.text_ram)                 /* 匹配所有.text_ram段的代码 */
    *(.text_ram.*)
    __TEXT_RAM_RUN_END__ = .;    /* RAM中的运行结束地址 */
    __TEXT_RAM_SIZE__ = __TEXT_RAM_RUN_END__ - __TEXT_RAM_RUN_START__;  /* 段大小 */
  } >RAM AT>FLASH  /* >RAM指定运行区域,AT>FLASH指定加载区域 */

  /* FLASH占位符段:大小与重定位段一致,确保链接器统计FLASH占用 */
  .text_ram_reserve :
  {
    . = ALIGN(4);
    __TEXT_RAM_LOAD_START__ = .; /* FLASH中的加载起始地址 */
    . = . + __TEXT_RAM_SIZE__;   /* 预留与重定位段相同的空间 */
    __TEXT_RAM_LOAD_END__ = .;   /* FLASH中的加载结束地址 */
  } >FLASH
  /* ------------------------------------------------------------- */

  /* 常规RAM段:初始化数据、未初始化数据 */
  .data : AT(__TEXT_END__)
  {
    __DATA_RUN_START__ = .;
    *(.data)
    *(.data.*)
    __DATA_RUN_END__ = .;
  } >RAM

  .bss :
  {
    __BSS_START__ = .;
    *(.bss)
    *(.bss.*)
    *(COMMON)
    __BSS_END__ = .;
  } >RAM
}

步骤3:验证内存占用

编译链接时,添加链接器选项--print-memory-usage,就能看到FLASH和RAM的占用统计,此时.text_ram的大小会同时出现在两个区域的已用空间中。你也可以用objdump -h <你的可执行文件>查看各个段的地址和大小,确认.text_ram和.text_ram_reserve的大小一致。

补充:启动代码中的复制逻辑

别忘了在启动代码中添加从FLASH到RAM的复制逻辑,比如用C实现:

void relocate_text_ram(void)
{
    uint32_t *src = (uint32_t *)__TEXT_RAM_LOAD_START__;
    uint32_t *dst = (uint32_t *)__TEXT_RAM_RUN_START__;
    uint32_t size = __TEXT_RAM_SIZE__;

    while (size > 0)
    {
        *dst++ = *src++;
        size -= sizeof(uint32_t);
    }
}

在系统初始化阶段(比如main()之前)调用这个函数,就能完成重定位。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:25:42