ARM GCC 链接器脚本,用于在 RAM 中启动时初始化 .data 部分

问题描述 投票:0回答:1

虽然我的问题涉及STM32的ARM GCC编译和链接,但它与GCC链接器脚本的正确编写更直接相关。

我有以下 STM32 链接器脚本:

MEMORY
{
  CCMSRAM (xrw) : ORIGIN = 0x10000000,   LENGTH = 32K
  RAM     (xrw) : ORIGIN = 0x20000000,   LENGTH = 128K
  ROM     (rx)  : ORIGIN = 0x08000000,   LENGTH = 512K
}

/* Sections */
SECTIONS
{

...

  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections into "RAM" Ram type memory */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
    
  } >RAM AT> ROM

...

}

这里

_sidata
.data
对于我想要实现的目标很重要。由于 STM32 微控制器具有单独的闪存(其中包含程序代码)和单独的 RAM(其中包含变量),因此该标准链接器脚本执行以下操作:

  1. 初始化变量最初包含在代码中并编程到闪存中。这是在链接描述文件中使用
    >RAM AT> ROM
    指定的。它们位于闪存中,从
    _sidata
    地址开始。
  2. 控制器启动时,启动代码将从
    _sidata
    地址开始的闪存中的变量复制到 RAM 到
    _sdata
    地址(
    .data
    区域的起始位置)。
  3. 之后过渡到
    main()
    。 一切都如预想的那样。

我想要实现的目标:相同的行为,但所有程序和数据都位于RAM中,并且每次启动时变量的初始化也以相同的方式完成。

所以,本质上,我希望有两个大小相等的内存区域,变量初始值位于

_sidata 
区域,同时拥有另一个大小相等的
.data
区域。每次启动时,启动代码还会将值从
_sidata 
复制到
_sdata
.data
区域的开头),恢复初始值,这些值可能自上次程序执行以来已发生变化。

如果我将 ld scrip

>RAM AT> ROM
中的这一行更改为
>RAM
(甚至更改为
>RAM AT> RAM
),则链接器会使
_sidata
_sdata
的地址相等,因此只有一个区域具有初始变量值,并且在执行主程序之前复制这些值实际上没有任何作用,因为这重写到了同一个地方。在下一次执行时,初始值已经丢失。

我尝试在示例和手册中寻找答案,但没有找到我需要的答案。我应该如何更改 ld 脚本以获得所需的结果?

gcc linker arm embedded stm32
1个回答
0
投票

您需要复制数据output部分。可以使用

VMA
LMA
来完成此任务(节
>AT
),但更简单的方法是复制内容。

  .data : ALIGN(4) {
    _sdata = .; *(.data) *(.data*) 
    /* ... omitted for brevity.*/
  } >RAM
  .init_data : ALIGN(4) {
    _sidata = .; *(.data) *(.data*) 
    /* ... omitted for brevity.*/
  } >RAM

请注意,STM32 代码生成和发布未正确使用

.ALIGN()
。我在这里解释这个

_sidata
只是一个变量名。如果您想要闪存(用于初始启动)并在运行时重新初始化,则可以仅使用闪存副本。这更加稳健,因为闪存更难以覆盖。看来它能满足你的愿望了?

我针对您的请求看到的用例是保持代码类似,以便将 JTAG 直接下载到 RAM。

© www.soinside.com 2019 - 2024. All rights reserved.