C 在GNU链接器脚本中创建额外的可重定位部分

C 在GNU链接器脚本中创建额外的可重定位部分,c,linker,arm,gnu,linker-scripts,C,Linker,Arm,Gnu,Linker Scripts,我试图在我的ARM MCU中为初始化数据创建一个额外的ram部分(在我的GNU链接器脚本中)。该部分将必须放置在一个已知的地址,以便我可以在MPU中为它设置特定的属性。 我对所有的链接器魔法都有点麻烦 内存划分如下: /* Memory Spaces Definitions */ MEMORY { rom (rx) : ORIGIN = 0x00420200, LENGTH = 0x001DFE00 ram (rwx) : ORIGIN = 0x2040

我试图在我的ARM MCU中为初始化数据创建一个额外的ram部分(在我的GNU链接器脚本中)。该部分将必须放置在一个已知的地址,以便我可以在MPU中为它设置特定的属性。 我对所有的链接器魔法都有点麻烦

内存划分如下:

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  :         ORIGIN = 0x00420200, LENGTH = 0x001DFE00
  ram (rwx) :         ORIGIN = 0x20400000, LENGTH = 0x0005e000
  ram_nocache_section (rwx) : ORIGIN = 0x2045e000, LENGTH = 0x00002000
  sdram(rwx):         ORIGIN = 0x70000000, LENGTH = 0x00200000
}
/* no cache section */
.ram_nocache :
{
   . = ALIGN(8);
   *(.ram_nocache)
} > ram_nocache_section
我要处理的是“ram_nocache_区”

我可以定义一个适当的部分,如下所示:

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  :         ORIGIN = 0x00420200, LENGTH = 0x001DFE00
  ram (rwx) :         ORIGIN = 0x20400000, LENGTH = 0x0005e000
  ram_nocache_section (rwx) : ORIGIN = 0x2045e000, LENGTH = 0x00002000
  sdram(rwx):         ORIGIN = 0x70000000, LENGTH = 0x00200000
}
/* no cache section */
.ram_nocache :
{
   . = ALIGN(8);
   *(.ram_nocache)
} > ram_nocache_section
这是可行的,但是产生的二进制是巨大的。0.5 GB。这是因为ram地址空间与闪存地址空间相隔0.5 GB。处理这种情况的方法是“重新定位”初始化的ram数据。脚本执行如下操作:

.text :
{
    ...
} > rom

. = ALIGN(4);
_etext = .;

.relocate : AT (_etext)
{
    . = ALIGN(4);
    _srelocate = .;
    *(.ramfunc .ramfunc.*);
    *(.data .data.*);
    . = ALIGN(4);
    _erelocate = .;
} > ram
这将在闪存和ram中神奇地分配初始化数据(和ram功能)。所以这很容易复制,对吗?像这样:

. = ALIGN(4);
_etext = .;

.relocate : AT (_etext)
{
    . = ALIGN(4);
    _srelocate = .;
    *(.ramfunc .ramfunc.*);
    *(.data .data.*);
    . = ALIGN(4);
    _erelocate = .;
} > ram

. = ALIGN(4);
_eramdata = .;

.relocate2 : AT ( _eramdata )
{
    . = ALIGN(4);
    _srelocate2 = .;
    . = ALIGN(8);
    *(.ram_nocache)
    . = ALIGN(4);
    _erelocate2 = .;
} > ram_nocache_section
这将进行编译,但生成的二进制文件仍然庞大。这是因为_eramdata符号以某种方式放在ram中,而不像_etext那样放在闪存中

那么。。。根据这一点,我应该可以这样做:

.relocate2 : AT ( _etext + SIZEOF(.data) + SIZEOF(.ramfunc) )
{
    . = ALIGN(4);
    _srelocate2 = .;
    . = ALIGN(8);
    *(.ram_nocache)
    . = ALIGN(4);
    _erelocate2 = .;
} > ram_nocache_section
但这不会编译。相反,我可以创建所需的结果,如下所示:

.relocate2 : AT ( _etext + 10k )
{
    . = ALIGN(4);
    _srelocate2 = .;
    . = ALIGN(8);
    *(.ram_nocache)
    . = ALIGN(4);
    _erelocate2 = .;
} > ram_nocache_section
然而,这是一个相当脆弱和浪费的解决办法


我如何正确地做到这一点?我想把“relocate2”部分放在常规“relocate”部分的旁边。没有任何多余的浪费或预定义的代码限制。

我自己可能已经找到了解决方案:

.relocate2 : AT ( _etext + SIZEOF(.relocate) )
{
    . = ALIGN(4);
    _srelocate2 = .;
    . = ALIGN(8);
    *(.ram_nocache)
    . = ALIGN(4);
    _erelocate2 = .;
} > ram_nocache_section

我肯定我已经试过了。但这似乎是我想要的。但仍然不是最优雅的解决方案。

我更喜欢这种结构:

. = ALIGN(4);
_etext = .;

.relocate : 
{
    . = ALIGN(4);
    _srelocate = .;
    *(.ramfunc .ramfunc.*);
    *(.data .data.*);
    . = ALIGN(4);
    _erelocate = .;
} > ram AT>rom

.relocate2 :
{
    . = ALIGN(4);
    _srelocate2 = .;
    . = ALIGN(8);
    *(.ram_nocache)
    . = ALIGN(4);
    _erelocate2 = .;
} > ram_nocache_section AT>rom

这两部分都必须改为AT>rom(无混合)。

阅读关于
NOINIT
属性的内容。我猜NOINIT类似于NOLOAD。这将阻止任何变量的初始化。这将解决问题(我已经检查过),但也会破坏程序。(我使用的是初始化的数据。)不清楚你想要什么。那么为什么不使用标准的
.data
部分呢?并且您没有指定加载内存。我想在指定地址创建一个与.data不同的节(以便我可以删除一些缓存属性等),您可以使用它来放置这些初始化节的LMA。您需要一些简单的汇编程序和一些LMA标签来执行LMA源到初始目标的
memcpy()
(任意一种方式)。然后链接器将为您执行此添加操作(与
\u etext
相同)。另一种方法是将所有内容放入
\u etext
,但为MMU/MPU提供填充。这将导致二进制文件有一个额外的填充大小。我确实尝试了AT>rom,但链接器抱怨部分重叠。显然,“AT>rom”和“section:AT(…)”构造相互冲突。我只是试着把两者都改成AT>rom。这似乎奏效了。(我将在下面发布代码。)将所有内容都放在.text中也不是一个坏主意。(它将创建一种“这是flash”部分。)