【问题标题】:GNU Linker Map File Giving Unexpected Load Addresses提供意外加载地址的 GNU 链接器映射文件
【发布时间】:2013-01-22 08:01:27
【问题描述】:

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

以下是链接描述文件的相关部分:

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
...
}

这是 MAP 文件的相关部分:

.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 load address 0x001003d4
.stack 0x00200040 0x200 load address 0x001003d4

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

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

在测试了一些东西后,我发现了以下内容:

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

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

(3) 当映射文件显示 .bss 和 .stack 部分的加载地址时,看起来它们实际上并没有占用 ROM 中的空间。 .stack 部分虽然有 0x200 字节长,但似乎并没有真正占用 ROM 中的空间,即使我为它指定填充值并在链接描述文件中在它之后放置一个部分。链接描述文件中跟随它的部分不会随着不同的堆栈大小移动。

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

另请参阅:Understanding the Location Counter of GNU Linker Scripts

【问题讨论】:

  • 总结一下: - 来自 YAGARTO 工具链的 binutils 版本 2.23.1 - 使用 NOLOAD 对地图文件没有任何影响。我使用NOLOAD,只需在链接器脚本中将.bss : 替换为.bss (NOLOAD) : 并将.stack : 替换为.stack (NOLOAD) :。 - 你在堆栈之后放置一个部分是正确的。我将 .text 部分移到那里,堆栈没有占用任何加载空间。 - 是的,整个问题都是关于地图输出的。它向我表明链接器正试图在 ROM 中为 .bss 和 .stack 提供一个加载地址(尽管我们刚刚发现这实际上并没有发生)。
  • 我也尝试过整理问题

标签: linker arm gnu


【解决方案1】:

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

NOLOAD 部分就像 编译/链接 时间 malloc()。您可以使用内存,只是不要期望那里有任何东西。对于BSS,您在链接描述文件中定义__bss_start____bss_end__,并编写一个简短的初始化例程来使用这些变量/地址清除此内存。

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

编辑:地图文件中的加载地址就像一个用于加载的位置计数器。加载地址是设置ld 放置东西的地方。 ld 如果它们的大小为零,则并没有真正将它们放在那里。地图输出在语言上不是明确的;我可以看到它是多么令人困惑,但ld 在创建输出二进制文件时做得正确。 BSS 通常由 gcc 在目标文件中标记为 NOLOAD,因此在示例中只有 stack 部分需要 NOLOAD。对于像 stack 这样的东西,一个部分并不是真正需要的,只需要一组符号声明就可以了。

【讨论】:

  • 谢谢,只有一件事我还不确定。我在我的问题中提到了它,但您可能错过了它(正如您所说的问题很长)。当我使用NOLOAD 时,映射文件仍会在 .stack 和 .bss 部分旁边显示加载地址。你是说当地图文件这样说的时候,它实际上是不正确的?
猜你喜欢
  • 1970-01-01
  • 2019-04-26
  • 2015-05-05
  • 2012-11-12
  • 2021-10-10
  • 2013-08-22
  • 2023-03-12
  • 2020-09-07
  • 1970-01-01
相关资源
最近更新 更多