Search code examples
gnuldbinutils

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


I am learning the GNU linker ld script sample about memory region alias.

I see the following ld script snippet:

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
}

One possible system memory region layout given in the sample is like this (C in that sample):

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*/

So,

PLACE 1 says .rodata MUST go into REGION_RODATA, that is 256M~257M

PLACE 2 says the .data section MUST be placed immediately after the .rodata section. So .data section MUST start from at most 257M.

But PLACE 3 says the .data section MUST goes into the REGION_DATA region. So .data section MUST start from at least 512M.

So how could it be possible?


Solution

  • The key concepts to understand this example are those of Virtual Memory Address (VMA) and Load Memory Address (LMA).

    The GNU Linker official documentation defines those two terms as follows.

    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.

    In the example, for all output sections but .data, the VMA and LMA addresses are the same. For section .data the LMA is specified by AT (rodata_end) while the VMA address is the first available address of the REGION_DATA memory region.

    With this in mind, we can read again the example and see that it leads to the situation represented below.

    ROM (alias REGION_TEXT)
    +---------+------------------------------+
    |  .text  |                              |
    +---------+------------------------------+
    
    ROM2 (alias REGION_RODATA)
    +-----------+---------+--------+
    |  .rodata  |  .data  |        |
    +-----------+---------+--------+
    
    RAM (alias REGION_DATA)
    +---------+--------+-----------+
    |  .data  |  .bss  |           |
    +---------+--------+-----------+
    

    The .data section appears twice: once in ROM2 and once in RAM. It is put at its load address (LMA) when loaded; subsequently it is moved to its virtual address before running the program. By the way, this is why, a few line later in the documentation you mentioned, we can read that

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