我正在开发一个嵌入式程序,我有一个自定义链接器脚本.该程序有效,但我注意到链接器如何在内存中放置几个部分可能有些不对劲.
以下是链接描述文件的相关部分:
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
...
}
Run Code Online (Sandbox Code Playgroud)
这是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__ = .
Run Code Online (Sandbox Code Playgroud)
所以从地图文件中我看起来像.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链接描述文件的位置计数器
你在找NOLOAD.请参阅Gnu LD输出部分类型.我现在读了你的整篇文章,我看到你的假设NOLOAD.使用NOLOAD,定义所有地址.如果您在"C"代码中使用它们,它们将从该地址加载.您必须提供一些启动代码,通常在清除BSS区域的汇编程序中.通常,您不希望初始化堆栈.
一NOLOAD节就像编译/链接时间malloc().你得到了使用的内存,只是不要指望任何东西.对于BSS,您可以在链接器脚本中定义__bss_start__并__bss_end__编写一个简短的初始化例程,以使用这些变量/地址清除此内存.
注意:所有内容都显示在地图文件中.它不会显示在生成的二进制文件中,也不会在ELF中显示数据.只是部分元信息将保存在ELF中.
编辑:地图文件中的加载地址就像一个用于加载的位置计数器.加载地址是ld设置放置东西的地方.ld如果它们的尺寸为零,那就不是真正把它放在那里.地图输出在语言上不是不明确的; 我可以看到它是如何混淆,但ld在创建输出二进制文件时做的正确.BSS通常NOLOAD在目标文件中用gcc 标记,因此在示例中只需要堆栈部分NOLOAD.对于类似堆栈的东西,实际上并不需要一个部分,只需要一组符号声明即可.