【问题标题】:What's the difference between these two linker script sections?这两个链接描述文件部分有什么区别?
【发布时间】:2019-11-27 22:13:39
【问题描述】:

我有一个涉及 .firmware_header 部分的 STM32 项目,该部分限制了我的应用程序映像的结尾。我正在尝试重新定位 .data 部分,以便它出现在 .firmware_header 部分之前,但由于某种原因,我在这样做时遇到了很多困难。

以下工作,但破坏了我用来签署图像的脚本,因为它不知道它需要在校验和计算中包含 .data 部分(LMA 在 RAM 中)。

  _sidata = .;
  .data_x : AT(_sidata) /* LMA address is _sidata (in FLASH) */
  {
    . = ALIGN(4);
    _sdata = .; /* data section VMA address */
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } > SRAM

  .firmware_header (_sidata + SIZEOF(.data_x)):
  {
    . = ALIGN(4);
    KEEP(*(.firmware_header))
    . = ALIGN(4);
  } > FLASH

这不起作用。即使所有地址(sidata、sdata、edata)都正确并且映像启动,但初始化数据存在问题,并且映像通常在开始运行后由于明显的原因硬失败。为什么会启动失败?要加载到内存中的数据的位置与前面的链接描述文件片段中的相同,存储数据在闪存中的位置也相同。

    .data_flash :
  {
    . = ALIGN(4);
    _sidata = .;
    *(.data*)
    . = ALIGN(4);
  } > FLASH

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

  .data_ram (NOLOAD) :
  {
    . = ALIGN(4);
    _sdata = .;
    . = . + SIZEOF(.data_flash);
    _edata = .;
    . = ALIGN(4);
  } > SRAM

这就是我在 reset_handler() 中将数据从闪存加载到内存中的方式:

void **pSource, **pDest;
for (pSource = &_sidata, pDest = &_sdata; pDest != &_edata; pSource++, pDest++)
    *pDest = *pSource;

我在这里缺少什么?这些在功能上不应该完全相同吗?

【问题讨论】:

  • 不清楚为什么您的脚本不适用于第一个解决方案。第一个解决方案是正确的方法。可能缺少的是数据部分指定 >SRAM AT>FLASH 以告诉链接器该部分位于闪存中但链接到 ram。你可以试试这个。

标签: gcc linker embedded stm32


【解决方案1】:

第一个脚本将所有 .data 段的字节放入闪存中的其部分,但将它们的所有地址解析为 RAM 中的运行时位置;这就是您的程序所需要的。要初始化变量,你需要将内容从闪存复制到RAM,你做什么。

第二个脚本解析所有.data段的地址,用于flash中的加载时间位置(如果我可以这么说的话);这是行不通的,因为您的程序在运行时无法写入这些位置。 NOLOAD 部分只是增加 RAM 中的位置指针,而不解析初始化变量的地址。

请查看交叉引用中的一些初始化变量(到一个不等于零的值)。使用您的第一个脚本,它将正确定位在 RAM 中的某个地址,使用您的第二个脚本,它将错误地定位在闪存中的某个地址。

【讨论】:

    猜你喜欢
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 2020-11-06
    • 2016-01-17
    • 2021-04-26
    • 2011-01-26
    • 2013-04-21
    相关资源
    最近更新 更多