如何理解有关链接器脚本的 GNU ld 手册中的此类示例?

How to understand such sample in GNU ld manual about linker script?

我正在学习 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.

那怎么可能呢?

理解此示例的关键概念是虚拟内存地址 (VMA)加载内存地址 (LMA)

The GNU Linker官方文档对这两个术语的定义如下。

Every loadable or allocatable output section has two addresses. The first is the VMA, or virtual memory address. This is the address the section will have when the output file is run. The second is the LMA, or load memory address. This is the address at which the section will be loaded.

在示例中,对于除 .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);随后它被移动到 运行 程序之前的虚拟地址。 顺便说一句,这就是为什么在您提到的文档后面的几行中,我们可以读到

It is possible to write a common system initialization routine to copy the .data section from ROM or ROM2 into the RAM if necessary.