我正在开发一个嵌入式程序,其中有一个自定义链接器脚本。该程序有效,但我注意到链接器在内存中放置几个部分的方式可能有问题。
以下是链接描述文件的相关部分:
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 如何生成其地图输出文件的错误吗?
另请参阅:了解 GNU 链接描述文件的位置计数器