Linker 提供意外加载地址的GNU链接器映射文件

Linker 提供意外加载地址的GNU链接器映射文件,linker,arm,gnu,Linker,Arm,Gnu,我正在开发一个嵌入式程序,其中有一个自定义链接器脚本。这个程序可以运行,但我注意到链接器在内存中放置几个部分的方式可能有问题 以下是链接器脚本的相关部分: MEMORY { ROM (rx) : ORIGIN = 0x00100000, LENGTH = 16k RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 4k } SECTIONS { /* Other sections go here. */ .data :

我正在开发一个嵌入式程序,其中有一个自定义链接器脚本。这个程序可以运行,但我注意到链接器在内存中放置几个部分的方式可能有问题

以下是链接器脚本的相关部分:

MEMORY {
    ROM (rx)    : ORIGIN = 0x00100000, LENGTH = 16k
    RAM (rwx)   : ORIGIN = 0x00200000, LENGTH = 4k
}

SECTIONS {
    /* Other sections go here. */
    .data : {
...
    } >RAM AT>ROM

    .bss : {
...
    } >RAM

    .stack : {
...
    } >RAM
...
}
以下是地图文件的相关部分:

.data           0x00200040        0x0 load address 0x001003d4
                0x001003d4                __data_load = LOADADDR (.data)
                0x00200040                __data_start = .
 *(.data)
 *(.data*)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _edata = .

.igot.plt       0x00200040        0x0 load address 0x001003d4
 .igot.plt      0x00000000        0x0 ./debug/sam7s_startup.o

.bss            0x00200040        0x0 load address 0x001003d4
                0x00200040                __bss_start__ = .
 *(.bss)
 *(.bss*)
 *(COMMON)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _ebss = .
                0x00200040                __bss_end__ = .
                0x00200040                PROVIDE (end, _ebss)
                0x00200040                PROVIDE (_end, _ebss)
                0x00200040                PROVIDE (__end__, _ebss)

.stack          0x00200040      0x200 load address 0x001003d4
                0x00200040                __stack_start__ = .

因此,从映射文件来看,.bss和.stack部分在ROM中获得加载地址。我认为这是因为以下两行:

.bss 0x00200040 0x0加载地址0x001003d4

.stack 0x00200040 0x200加载地址0x001003d4

这是不好的,因为它们没有必要占用ROM中的空间。尽管.bss部分现在是空的,但将包含未初始化的全局变量,这些变量在代码中将设置为零。堆栈也只是RAM的一部分,将在代码中初始化。所以这两个部分都不需要占用ROM中的空间

所以我的问题是,阻止.bss和.stack加载到ROM中的正确方法是什么?是否必须将.bss和.stack部分的结尾从
>RAM
更改为
>ramat>RAM
?这似乎有点多余

在测试了一些东西之后,我发现了以下几点:

(1) 使用
(空载)
属性(例如,将
.stack:
替换为
.stack(空载):
)仍然会导致映射文件显示.stack和.bss部分的ROM加载地址

(2) 如上所述,在RAM处指定
RAM
,确实会阻止映射输出显示.stack和.bss部分的ROM加载地址

(3) 当映射文件显示.bss和.stack部分的加载地址时,它们似乎实际上并不占用ROM中的空间。尽管.stack部分的长度为0x200字节,但似乎并不实际占用ROM中的空间,即使我为其指定了填充值并在链接器脚本中在其后面放置了一个部分。链接器脚本中紧随其后的部分不会随着堆栈大小的不同而移动

因此,可能映射文件输出的含义与我认为的不同,并且.stack和.bss部分实际上根本没有在ROM中被赋予加载地址。在尝试了一些东西之后,它肯定会以这种方式出现。知道为什么映射输出使其看起来像是给定了ROM加载地址一样仍然很有趣,尤其是在使用
(NOLOAD)
时。这可能只是LD如何生成地图输出文件的一个错误吗


另请参见:

您正在查找的
空载
。看见我现在读了你的整篇文章,我看到你假设了
空载
。使用
NOLOAD
,定义所有地址。如果在“C”代码中使用它们,它们将从该地址加载。您必须提供一些启动代码,通常在清除BSS区域的汇编程序中。通常,您不希望堆栈被初始化

NOLOAD
部分类似于编译/链接时
malloc()
。你有足够的内存去使用,只是别指望那里会有什么。对于BSS,您可以在链接器脚本中定义
\uuuuu BSS\u start\uuuu
\uuuu BSS\u end\uuu
,并编写一个简短的初始化例程,以使用这些变量/地址清除此内存

注意:所有内容都显示在地图文件中。它不会在生成的二进制文件中显示,也不会在ELF中显示数据。只有部分元信息将保存在ELF中


编辑:地图文件中的加载地址类似于用于加载的位置计数器。加载地址是
ld
设置为放置内容的位置
ld
并不是真的把零尺寸的东西放在那里。地图输出在语言上并非不含糊;我可以看出这是多么令人困惑,但是
ld
在创建输出二进制文件时做得很正确BSS通常由gcc在目标文件中标记为
NOLOAD
,因此在本例中,只有堆栈部分需要
NOLOAD
。对于类似于堆栈的东西,实际上并不需要一个部分,只需要一组符号声明就可以了。

谢谢,有一件事我仍然不确定。我在我的问题中提到了这一点,但你可能错过了(正如你所说的,这个问题很长)。当我使用
NOLOAD
时,映射文件仍然在.stack和.bss节旁边显示加载地址。你是说当地图文件这样说时,它实际上并不正确吗?总结一下:-来自YAGARTO工具链的binutils版本2.23.1-使用
NOLOAD
对地图文件没有影响。我使用了
NOLOAD
,只需将链接器脚本中的
.bss:
替换为
.bss(NOLOAD):
.stack:
替换为
.stack(NOLOAD):
关于在堆栈后放置节,您是正确的。我将.text部分移到了那里,堆栈没有占用任何加载空间。-是的,整个问题是关于地图输出的。它向我暗示,链接器正试图在ROM中给.bss和.stack一个加载地址(尽管我们刚刚发现这实际上并没有发生)。我也试图整理这个问题