我正在学习GNU链接器ld脚本sample about memory region alias。
我看到以下ld脚本片段:
SECTIONS
{
.text :
{
*(.text)
} > REGION_TEXT
.rodata :
{
*(.rodata)
rodata_end = .;
} > REGION_RODATA <=========== PLACE 1
.data : AT (rodata_end) <=========== PLACE 2
{
data_start = .;
*(.data)
} > REGION_DATA <=========== PLACE 3
data_size = SIZEOF(.data);
data_load_start = LOADADDR(.data);
.bss :
{
*(.bss)
} > REGION_BSS
}
样本中给出的一个可能的系统内存区域布局是这样的(该示例中的 C ):
MEMORY
{
ROM : ORIGIN = 0, LENGTH = 2M /*0M ~ 2M*/
ROM2 : ORIGIN = 0x10000000, LENGTH = 1M /*256M ~ 257M*/
RAM : ORIGIN = 0x20000000, LENGTH = 1M /*512M ~ 513M*/
}
REGION_ALIAS("REGION_TEXT", ROM); /*0M ~ 2M*/
REGION_ALIAS("REGION_RODATA", ROM2); /*256M ~ 257M*/
REGION_ALIAS("REGION_DATA", RAM); /*512M ~ 513M*/
REGION_ALIAS("REGION_BSS", RAM); /*512M ~ 513M*/
所以,
PLACE 1
说.rodata
必须进入REGION_RODATA
,即256M~257M
PLACE 2
表示.data
部分必须在.rodata
部分之后立即 。因此,.data
部分必须从 最多 257M开始。
但是PLACE 3
说.data
部分必须进入REGION_DATA
区域。因此.data
部分必须从 至少 512M开始。
那怎么可能呢?
答案 0 :(得分:2)
理解此示例的关键概念是虚拟内存地址(VMA)和加载内存地址(LMA)。
The GNU Linker官方文档将这两个术语定义如下。
每个可加载或可分配的输出部分都有两个地址。该 首先是 VMA ,或虚拟内存地址。这是地址了 部分将在输出文件运行时生成。第二个是 LMA , 或加载内存地址。这是该部分的地址 加载。
在该示例中,对于除.data
之外的所有输出节,VMA和LMA地址是相同的。对于.data
部分,LMA由AT (rodata_end)
指定,而VMA地址是REGION_DATA
内存区域的第一个可用地址。
考虑到这一点,我们可以再次阅读该示例,并看到它导致下面所示的情况。
ROM (alias REGION_TEXT)
+---------+------------------------------+
| .text | |
+---------+------------------------------+
ROM2 (alias REGION_RODATA)
+-----------+---------+--------+
| .rodata | .data | |
+-----------+---------+--------+
RAM (alias REGION_DATA)
+---------+--------+-----------+
| .data | .bss | |
+---------+--------+-----------+
.data
部分出现两次:一次在ROM2
,一次在RAM
。加载时将其置于加载地址(LMA);随后在运行程序之前将其移动到其虚拟地址。
顺便说一句,这就是为什么,在你提到的文档后面几行,我们可以读到
可以编写一个通用的系统初始化例程进行复制 如有必要,将ROM或ROM2中的.data部分放入RAM中。