How to understand the relation between LMA, VMA and FileOffset?

0

Below is the linker script from an ARM-based OS.

ENTRY(__entry) /*kernel entry (kernel/asm/boot.S)*/

/*kernel will be loaded at this address after boot*/
INCLUDE linker.ld

SECTIONS
{
    /*kernel will be compiled with virtual address base at 2GB*/
    . = 0x80000000 + start_address; /*2GB + start_address = (0x80010000)*/
    PROVIDE(_kernel_start = .); /*defined at kernel/include/kernel.h, set to 0x80010000*/

 .text : AT(start_address) 
    {
        *(.text)
    }

    .data : 
    { 
        *(.data) 
    }

    .bss : 
    { 
        *(.bss COMMON)
    }
    . = ALIGN(8);
    PROVIDE(_fb_start = .); 
    . += framebuffer_size;

    PROVIDE(_kernel_end = .); /*defined at kernel/include/kernel.h*/
}

It will generate an ELF file with sections like this:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000c610  80010000  00010000  00010000  2**2 <=== LMA and FileOffset are affected starting from this section.
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       0000037d  8001c610  0001c610  0001c610  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00004000  80020000  00020000  00020000  2**14
                  CONTENTS, ALLOC, LOAD, DATA
  3 .got          00000024  80024000  00024000  00024000  2**2
                  CONTENTS, ALLOC, LOAD, DATA

I changed the linker script to below just for experiment:

ENTRY(__entry) /*kernel entry (kernel/asm/boot.S)*/

/*kernel will be loaded at this address after boot*/
INCLUDE linker.ld

SECTIONS
{
    /*kernel will be compiled with virtual address base at 2GB*/
    . = 0x80000000 + start_address; /*2GB + start_address = (0x80010000)*/
    PROVIDE(_kernel_start = .); /*defined at kernel/include/kernel.h, set to 0x80010000*/

 .text : /*AT(start_address) */ <--------------- Here Commented!
    {
        *(.text)
    }

    .data : AT(start_address) <--------------- Move it to here!
    { 
        *(.data) 
    }

    .bss : 
    { 
        *(.bss COMMON)
    }
    . = ALIGN(8);
    PROVIDE(_fb_start = .); 
    . += framebuffer_size;

    PROVIDE(_kernel_end = .); /*defined at kernel/include/kernel.h*/
}

It will generate an ELF file with sections like this:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000c610  80010000  80010000  00020000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       0000037d  8001c610  8001c610  0002c610  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00004000  80020000  00010000  00010000  2**14 <=== LMA and FileOffset are affected starting from this section.
                  CONTENTS, ALLOC, LOAD, DATA
  3 .got          00000024  80024000  00014000  00014000  2**2
                  CONTENTS, ALLOC, LOAD, DATA

We can see the .text and .rodata sections LMA is not affected. Only the .data section and later sections are affected by the AT() command.

So it gives me a feeling that the VMA and LMA calculation during linking is independent of each other.

If there's no AT() command, the LMA and VMA will be the same. Once there's a AT() command, the sections that after it will be affected.

I didn't find detailed description about this behavior in the Using ld doc. Am I correct?

And why the FileOffset is also changed by the AT() command? The .text and .data sections are swapped with regard to FileOffset.

linker
ld
binutils
asked on Stack Overflow May 4, 2019 by smwikipedia

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0