虽然我的问题涉及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(其中包含变量),因此该标准链接器脚本执行以下操作:
>RAM AT> ROM
指定的。它们位于闪存中,从 _sidata
地址开始。_sidata
地址开始的闪存中的变量复制到 RAM 到 _sdata
地址(.data
区域的起始位置)。main()
。
一切都如预想的那样。我想要实现的目标:相同的行为,但所有程序和数据都位于RAM中,并且每次启动时变量的初始化也以相同的方式完成。
所以,本质上,我希望有两个大小相等的内存区域,变量初始值位于
_sidata
区域,同时拥有另一个大小相等的 .data
区域。每次启动时,启动代码还会将值从 _sidata
复制到 _sdata
(.data
区域的开头),恢复初始值,这些值可能自上次程序执行以来已发生变化。
如果我将 ld scrip
>RAM AT> ROM
中的这一行更改为 >RAM
(甚至更改为 >RAM AT> RAM
),则链接器会使 _sidata
和 _sdata
的地址相等,因此只有一个区域具有初始变量值,并且在执行主程序之前复制这些值实际上没有任何作用,因为这重写到了同一个地方。在下一次执行时,初始值已经丢失。
我尝试在示例和手册中寻找答案,但没有找到我需要的答案。我应该如何更改 ld 脚本以获得所需的结果?
您需要复制数据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。