我正在开发一个嵌入式程序,其中有一个自定义链接器脚本。该程序可以工作,但我注意到链接器在内存中放置几个部分的方式可能有问题。
以下是链接描述文件的相关部分:
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
to >RAM AT>RAM
?这似乎有点多余。
在测试了一些东西之后,我发现了以下内容:
(1) 使用(NOLOAD)
属性(例如通过替换.stack :
with .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 链接器脚本的位置计数器 https://stackoverflow.com/questions/13831462/understanding-the-location-counter-of-gnu-linker-scripts